Legal Information

Messaging Application Programming Interface (MAPI) Programmer's Reference

Information in this document is subject to change without notice. This document is provided for informational purposes only and Microsoft Corporation makes no warranties, either express or implied, in this document. The entire risk of the use or the results of the use of this document remains with the user. The names of companies, products, people, characters, and/or data mentioned herein are fictitious and are in no way intended to represent any real individual, company, product, or event, unless otherwise noted. Complying with all applicable copyright laws is the responsibility of the user. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, without the express written permission of Microsoft Corporation. If, however, your only means of access is electronic, permission to print one copy is hereby granted.

Microsoft may have patents or pending patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. The furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property rights except as expressly provided in any written license agreement from Microsoft.

© 1996-1998 Microsoft Corporation. All rights reserved.

Microsoft, Microsoft Press, MS, MS-DOS, Visual Basic, Visual C++, Windows, Win32, Win32s, and Windows NT are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries.

Macintosh is a registered trademark of Apple Computer, Inc.

Intel is a registered trademark of Intel Corporation.

Other product and company names mentioned herein may be the trademarks of their respective owners.


Finding What You Need

The Messaging Application Programming Interface (MAPI) Programmer's Reference is the documentation that accompanies the Platform SDK.

The MAPI Programmer's Reference is organized as follows:

  • Quick Start Procedures

    Topics in this section describe tasks commonly performed using the Platform SDK and include design tasks, implementation tasks, and references to sample source code. These procedures are not intended to supply the actual implementation details.

  • About Samples and Tools

    Topics in this section describe the MAPI sample source code included in the Platform SDK documentation and SDK tools.

  • Guide

    Aside from a discussion of key concepts and the MAPI architecture, this section includes topics for developers using CMC and Simple MAPI, developers using MAPI to write a client application or a service provider and developers working with forms. There are also topics that describe, at a conceptual level, the use and implementation of objects, interfaces, properties, and tables.

  • Reference

    This section consists of alphabetic listings of the MAPI programming elements such as interfaces, functions, properties and structures. Where appropriate, the reference pages include syntax, parameters and return values for each API element.

  • Appendixes

    This section includes a wide range of topics, some of which are of interest to all MAPI programmers and some that are of interest to small groups of programmers.

  • Glossary

    This section provides definitions for commonly used MAPI terms and cross references to related topics in the Guide and Reference.


Finding API Elements

There are several ways to find the reference topic for an API element:

  • In the Contents pane, open the appropriate Reference section and browse the alphabetic list.
  • In the Contents pane, open the Appendixes section. Open the Functionality Groups section, choose the type of element that interests you, and browse the alphabetic list.
  • On the toolbar, click the [image] button. In the list box that appears, type the name of the programming element you want to see, or scroll through the list and select a keyword. As you type, the list automatically scrolls to the word that most closely matches the text you are typing.


Finding Header Information

Each Reference topic includes a Quick Info table that names the MAPI header file where the API element is defined. The MAPI header files that are commonly used by developers include:

Header file | Description of contents
MAPI.H | Definitions of structures, constants, and error values for Simple MAPI
MAPICODE.H | Definitions of status codes for error values
MAPIDBG.H | Definitions of macros for debugging
MAPIDEFS.H | Definitions of commonly used event types, property types, flags, structures, interfaces
MAPIFORM.H | Definitions of forms elements
MAPIGUID.H | Definitions of GUIDs
MAPISPI.H | Definitions of flags and interfaces implemented by MAPI for service providers and message services
MAPITAGS.H | Definitions of property tags
MAPIUTIL.H | Definitions of utility interfaces and functions
MAPIVAL.H | Definitions of validation macros
MAPIX.H | Definitions of flags and interfaces implemented by MAPI for clients


Finding Lists of Required Properties

Lists of required and optional properties are documented in several places:

  • See the following interfaces for lists of properties associated with objects that support these interfaces:

    IABContainer : IMAPIContainer

    IAttach : IMAPIProp

    IDistList : IMAPIContainer

    IMailUser : IMAPIProp

    IMAPIContainer : IMAPIProp

    IMAPIStatus : IMAPIProp

    IMessage : IMAPIProp

    IMsgStore : IMAPIProp

    IProfSect : IMAPIProp

  • For lists of properties required on tables, see the documentation for each type of table in Tables.
  • For lists of required and optional message properties for message classes defined by MAPI, see:

    Required Properties for All Messages

    Required Report Message Properties

    Optional Report Message Properties

    Recipient Properties for All Messages

    Recipient Properties for Delivery Status Reports

  • For lists of properties related by functionality, browse the subtopics in Property Groups.


Finding Information About Objects

Information about objects is documented in various sections. Because nearly all MAPI objects expose a single MAPI interface, the approach is to treat objects and the interfaces that they expose as synonymous.

You can find information about objects and interfaces in the following sections:

  • MAPI Interfaces in the Reference. For example, locate information about implementing and using a folder under its standard interface, IMAPIFolder.
  • Objects and Interfaces in the Guide. This section introduces the Component Object Model as it relates to MAPI, describes MAPI's object hierarchy and containment model, maps objects to interfaces, and describes implementation responsibilities.
  • Properties in the Guide. This section describes how objects manage properties and how clients work with them.
  • Tables in the Guide. This section describes in detail how to implement and use a table object and discusses the composition and purpose of the different types of tables.
  • Forms in the Guide. This section describes the various objects used in the implementation and use of forms.
  • MAPI Programming Basics in the Guide. This section provides information about the following types of objects:

    Folders

    Messages

    Attachments

    Recipients

    Status objects

    Profile and message service objects

  • Developing a Client Application in the Guide. This section describes how to use the objects to implement a MAPI client application.
  • Service Provider Basics in the Guide. This section describes how to use a support object and a progress object and implement a status object and display table.
  • Developing an Address Book Provider in the Guide. This section describes how to implement the address book logon and provider objects, address book containers, messaging users, distribution lists, and related tables.
  • Developing a Transport Provider in the Guide. This section describes how to implement the transport logon and provider objects, status object, TNEF object, and folders.
  • Developing a Message Store Provider in the Guide. This section describes how to implement the message store logon and provider objects, message stores, folders, messages, attachments, recipients, and related tables.
  • Developing MAPI Form Servers in the Guide. This section describes how to implement form objects.


Finding Other Documentation

Articles, information about Internet resources for MAPI developers, and instructions for installing and using MAPI samples and tools can be found on the Microsoft For Developers Only Web site. Go to the Win32 Development topic from the home page. At the bottom of the Win32 home page, click Messaging (MAPI).

For more information about OLE programming, see Inside OLE, Second Edition, by Kraig Brockschmidt (Redmond, WA: Microsoft Press, 1995) or the COM and ActiveX Object Services section in the Platform SDK.

For more information about programming with Microsoft® Visual Basic® programming system, see your Visual Basic documentation.


Document Conventions

This manual uses the following typographic conventions:

Convention | Description
monospace
 Indicates source code, structure syntax, examples, user input, and program output. For example,
ptbl->SortTable(pSort, TBL_BATCH);
Bold | Indicates an interface, method, structure, or other keyword in MAPI, the Microsoft® Windows® operating system, the OLE application programming interface, C, or C++. For example, SpoolerYield is a MAPI method. Within discussions of syntax, bold type indicates that the text must be entered exactly as shown.
Italic | Indicates placeholders, most often method or function parameters; these placeholders stand for information that must be supplied by the implementation or the user. For example, lpMAPIError is a MAPI method parameter.
UPPERCASE | Indicates MAPI flags, return values, and properties. For example, MAPI_UNICODE is a flag, S_OK is a return value, and PR_DISPLAY_NAME is a property. In addition, uppercase letters indicate filenames, segment names, registers, and terms used at the operating-system command level.
( ) Indicate one or more parameters that you pass to a function, in syntax.
[ ] Indicate optional syntax items. Type only
the syntax within the brackets, not the brackets themselves.

Note The interface syntax in this book follows the variable-naming convention known as Hungarian notation, invented by the programmer Charles Simonyi. Variables are prefixed with lowercase letters that indicate their data type. For example, lpszProfileName is a long pointer to a zero-terminated string name ProfileName. For more information about Hungarian notation, see Programming Windows 95 by Charles Petzold and Code Complete by Steve McConnell.


Quick Start Procedures

Topics in the Quick Start Procedures section describe tasks commonly performed using the Platform SDK. Each topic is divided into three sections: design tasks, implementation tasks, and references to sample source code.

These procedures are not intended to supply the actual implementation details. Instead, they provide a high-level overview of design decisions you will need to make and refer you to the necessary topics.

Adding a Send Command to an Application

Adding Document Routing to an Application

Creating a New Interpersonal (IPM) Message Class

Creating a New Interprocess (IPC) Message Class

Creating and Configuring a Profile

Incorporating Formatted Text and Attachments

Finding a Message in a Message Store

Using Message Filtering to Manage Messages

Finding Information About a User in the Address Book


Adding a Send Command to an Application

Being able to add a Send command to a document-based application's File menu is a Microsoft Windows 95 logo requirement. The same logic applies to sending a message from any application.

Design Tasks

  1. Decide whether to use Simple MAPI, CMC, MAPI, or the Active Messaging Library. See Selecting a Client Interface.
  2. Decide when to load and unload the selected interface, and when to create and destroy its session. You should share the messaging client's session, if it is active. See MAPI Sessions.

Implementation Tasks

  1. Determine whether the Send command should be enabled. Installation of messaging support in the operating system is optional, and your Send command should be disabled if the selected interface is not available. See Determining Which Client Interfaces are Installed.
  2. Load the selected interface DLL and the entry points you will need. See one of the following topics, depending upon which interface you have selected:
    • For Simple MAPI, see Initializing a Simple MAPI Client.
    • For CMC, see Starting a CMC Session.
    • For MAPI, see Initializing MAPI and Initializing OLE for Use with MAPI.
    • For the Active Messaging Library, no explicit load step is necessary. Simply instantiate one of the top-level objects, MAPI.Session or MAPI.Message.
  3. Send a document using the selected interface. See one of the following topics, depending upon which interface you have selected:
    • For Simple MAPI, see Sending Messages with Simple MAPI.
    • For CMC, see Sending Messages with CMC.
    • For the Active Messaging Library, see Creating and Sending a Message.
    • For MAPI, several steps are necessary:
    1. Open the default message store. See Opening a Message Store.
    2. Open the Outbox. See Opening a Folder.
    3. Add recipients to the message's recipient table. See Recipients.
    4. Add the document to the message as an attachment. See Attachments.
    5. Optionally, add text to the message. See PR_BODY.
    6. Send the message. See Sending Messages with MAPI.
    7. Release all the objects created in the preceding steps.

About Sample Source Code

See the following topics:

Sample CMC Client

Sample Routing Client

Sample RTF Utility

Sample Simple MAPI Client

Sample Timecard Application


Adding Document Routing to an Application

Document routing — adding a Route command or another form of document routing support to a File menu in a document-based application — can be used for many purposes, but all involve defining a list of people who are to read and act on information in the document in a specific order.

The following discussion assumes you want to base your routing application on an existing document-based application. If you prefer to base it on a messaging client, see also Creating a New Interpersonal (IPM) Message Class.

Design Tasks

  1. Decide whether to use Simple MAPI, CMC, MAPI, or the Active Messaging Library. See Selecting a Client Interface.

    If your application requires routing across messaging domain boundaries, you must use MAPI or the Active Messaging Library and store the routing information in named properties on the message. See Sending Across Messaging Domains. If you use the Active Messaging Library, the routing information must be stored in the message's Fields collection using five special property sets. See Customizing a Folder or Message and Fields Collection Object.

    If you choose to use Simple MAPI or CMC, the routing information can be stored in a file attached to your message. For Simple MAPI, see Handling Attachments with Simple MAPI. For CMC, see Handling Attachments with CMC.

  2. Design the message properties and the commands — called "verbs" in MAPI — specific to your routing functionality.

Implementation Tasks

  1. Choose the message class name. It should begin with IPM. See Message Classes.
  2. Use the MAPI address book dialog box to let the user add names to the routing list. See the IAddrBook::Address method and ADRPARM and ADRLIST structures.
  3. Store the routing list in the message, an attached file, or the document itself, as appropriate.
  4. Support your routing verbs with message — or document — properties that refer to entries in the routing list.

About Sample Source Code

See the following topics:

Sample Routing Client

Sample Timecard Application


Creating a New Interpersonal (IPM) Message Class

There are several ways to create a new message class used for person-to-person communication. By using MAPI properties to structure message content, you avoid writing code to parse message text or a binary attachment.

Design Tasks

  1. Decide whether yours is an interpersonal messaging (IPM) application or a type of interprocess communication (IPC) application. There is an enormous variety of applications; following is a basic list of types and examples. For more information about IPC applications, see Creating a New Interprocess (IPC) Message Class.
    • Person-to-person. A person initiates the exchange of messages, and another person responds. This includes traditional e-mail as well as more structured exchanges such as document routing or expense approval.
    • Person-to-machine. A person initiates the exchange of messages, and a machine responds. Examples include submitting a database query by e-mail and subscribing to a mailing list.
    • Machine-to-person. A machine initiates the exchange of messages, and a person responds. Examples include news feeds and other types of document distribution, and opinion surveys.
    • Machine-to-machine. A machine initiates the exchange of messages, and another machine responds. Examples include link heartbeat monitoring, directory and database replication.
    • A more complex pattern with both people and machines in the route.
    • A more complex pattern where, instead of being transmitted, the message may be posted directly into a public folder or bulletin board forum supported by a message store for consumption by other readers, an administrator, or a software agent.

    Logically, person-to-person applications, machine-to-person applications, and applications that post to public forums should be designated IPM, while person-to-machine and machine-to-machine applications are IPC message classes. The only real difference is that IPM messages in a message store are visible to messaging clients, while IPC messages usually are not. Anything that requires a person to respond must use an IPM message class. Applications involving a more complex pattern including people and machines often involve a mix of IPM and IPC messages.

  2. Choose the message class name, beginning it with IPM. or IPC. according to the preceding guidelines.
  3. Choose the application framework for sending and reading your messages. Alternatives include:
    • A form. A form is a MAPI object that is integrated into messaging clients; it can create, display, print, and perform custom commands — called "verbs" in MAPI — on a particular type of message. Forms take maximum advantage of integration with the messaging client. See Forms.
    • A standalone application. This gives you the greatest control over the user interface to your messages but also requires the most work in creating and distributing your application and in making it easy for your users to find.
    • A client extension. This is a compromise. An extension is easier for users to discover than a standalone application and in some respects easier to write than a form, but the integration with the client is less complete than with a form. See Advantages of Extending Microsoft Exchange.
  4. Decide whether to use Simple MAPI, CMC, MAPI, or the Active Messaging Library. See Selecting a Client Interface. In addition to the considerations listed there, you must think about whether that interface fits well into the application framework you have chosen. For instance, both forms and extensions must use or furnish several COM interfaces which are not easily supported by Visual Basic programs.
  5. Define properties specific to your message class. Decide whether to use named properties or properties from the 0x6800-0x7fff range. See About Property Identifiers and Named Properties. Properties that contain e-mail addresses should be stored in a special way to provide for translation when changing messaging domains. See Sending Across Messaging Domains.

    Consider the need for interoperability with messaging clients that can be only message text. It may be advisable to duplicate some or all of your message's properties in the message text if you expect the message to be read by people using such messaging clients.

  6. Define the commands — called "verbs" in MAPI — specific to your message class, and choose which standard verbs to implement. See Form Verbs.
  7. Choose a distribution mechanism. For a standalone application, this generally involves making an executable and any necessary auxiliary files available to your users. Additional steps are necessary if you are implementing a form, including which library to register it in. See Form Libraries. Additional steps are also necessary if you are implementing a client extension. See Registering Extensions.

Implementation Tasks

All IPM message classes should honor common IPM client options for disposition of sent messages and other features.

To implement a form
  1. Choose a class identifier (CLSID) for the form. You can use the tool UUIDGEN.EXE for this purpose. See Using UUIDGEN.EXE.
  2. Choose a message class name for the form. See Message Classes.
  3. Create an .EXE file that acts as a COM server for the form, registered with the form's class identifier. It must implement the OLE interface IClassFactory, and the IMAPIForm and IPersistMessage interfaces; it may optionally implement the IMAPIFormAdviseSink and IMAPIFormFactory interfaces. See Implementing the IClassFactory Interface for Form Servers. The class factory's CreateInstance method must return an IMAPIForm interface; that form object's QueryInterface method must be capable of returning an IPersistMessage interface.
  4. Create a .CFG file listing the form's class identifier, message class, properties, verbs, extensions, and so forth. See File Format of Form Configuration Files.
  5. For each user of your form, make the .EXE file and any auxiliary files available, and register the .CFG file in a form library using PDKIN.EXE, INSTFORM.EXE, or your own code. See Form Libraries. If using the local form library, you must also register your .EXE file as a COM server for the form's class identifier, using REGEDIT.EXE.

For more information, see Developing MAPI Form Servers.

To add an extension to the messaging client
  1. Decide which client contexts your extension should be available in, and whether your extension requires a specific message service to be available. See How Extensions Work.
  2. Create a DLL with an entry point that returns an extension object — an object that implements the IExchExt interface and any other required interfaces. Implement the IExchExt interface and any other required interfaces.
  3. For each user of your extension, make the DLL and any auxiliary files available, and register your extension in the system registry or WIN.INI file. See Registering Extensions.

For more information, see Command Extensions.

To create a standalone application using MAPI
  1. Verify that MAPI is installed before proceeding if your installation process does not guarantee that MAPI is installed. See Installing MAPI.
  2. Load and initialize the MAPI DLL. See Initializing MAPI and Initializing OLE for Use with MAPI.
  3. Log on to MAPI using the messaging client's session if available. See Logging On.
  4. Open the user's default message store, Inbox and Outbox folders. See Opening a Message Store and Opening a Folder.
  5. Create and send a message using the following steps:
    1. Create a message in the Outbox folder using the IMAPIFolder::CreateMessage method.
    2. Add recipients to the message's recipient table. See Recipients.
    3. Add the document to the message as an attachment. See Attachments.
    4. Optionally, add text to the message. See the PR_BODY property.
    5. Send the message. See Sending Messages with MAPI.
  6. Scan the Inbox for new messages using the following steps:
    1. Optionally, force any incoming messages to be downloaded. See IMAPIStatus::FlushQueues.
    2. Open the Inbox folder's contents table.
    3. Restrict the contents table to messages of interest to your application.
    4. Optionally, register for new mail notifications on the message store object to be advised of further incoming messages.
  7. For each user of your application, make the .EXE file and any auxiliary files available.

About Sample Source Code

See the following topics:

Sample Custom Sendable Form

Sample Command Extension

Sample Routing Client

Sample Form

Sample Timecard Application


Creating a New Interprocess (IPC) Message Class

Structured messages can be sent and read between programs, or between programs and users. By using MAPI properties to structure message content, you avoid writing code to parse message text or a binary attachment.

Design Tasks

  1. Decide whether yours is an interpersonal messaging (IPM) application or a type of interprocess communication (IPC) application. There is an enormous variety of applications; following is a basic list of types and examples. For more information about IPM applications, see Creating a New Interpersonal (IPM) Message Class.
    • Person-to-person. A person initiates the exchange of messages, and another person responds. Examples include traditional e-mail as well as more structured exchanges such as document routing or expense approval.
    • Person-to-machine. A person initiates the exchange of messages, and a machine responds. Examples include submitting a database query by e-mail and subscribing to a mailing list.
    • Machine-to-person. A machine initiates the exchange of messages, and a person responds. Examples include news feeds and other types of document distribution, and opinion surveys.
    • Machine-to-machine. A machine initiates the exchange of messages and another machine responds. Examples include link heartbeat monitoring, directory and database replication.
    • A more complex pattern with both people and machines in the route.
    • A more complex pattern where, instead of being transmitted, the message may be posted directly into a public folder or bulletin board forum supported by a message store, for consumption by other readers, an administrator, or a software agent.

    Logically, person-to-person applications, machine-to-person applications, and applications that post to public forums should be designated IPM, while person-to-machine and machine-to-machine applications are IPC message classes. The only real difference is that IPM messages in a message store are visible to messaging clients, while IPC messages usually are not. Anything that requires a person to respond must use an IPM message class. Applications involving a more complex pattern including people and machines often involve a mix of IPM and IPC messages.

  2. Decide whether to use Simple MAPI, CMC, MAPI, or the Active Messaging Library. See Selecting a Client Interface.
  3. Decide whether your application can use the same profile as the messaging client or whether you must create one. See Creating and Configuring a Profile.
  4. Choose the message class name, beginning it with IPM. or IPC. according to the guidelines established previously.
  5. Define properties specific to the message class. Decide whether to use named properties or properties from the 0x6800-0x7fff range. See About Property Identifiers and Named Properties. Properties that contain e-mail addresses should be stored in a special way to provide for translation when changing messaging domains. See Sending Across Messaging Domains.

    One difference between IPM and IPC applications is that machines are much less tolerant of variations in message format than people are. Compatibility with messaging clients that can view only message text is often required for IPM applications, but IPC applications typically use MAPI properties to structure information in their messages and require MAPI everywhere. Nevertheless, for machine-to-person applications it may be necessary to duplicate some or all of the properties in the message text for compatibility with messaging clients that can view only message text.

  6. Define the commands — called "verbs" in MAPI — specific to your message class, and choose which standard verbs to implement.
  7. Decide how to handle sent messages and reports. It is usually not appropriate for IPC applications to save outbound messages in the IPM Sent Items folder, but the application may need to save outbound messages in a hidden folder for tracking purposes. See Hidden Folders.

Implementation Tasks

  1. Load the selected interface DLL and the entry points you will need. See one of the following topics, depending upon which interface you have selected.
    • For Simple MAPI, see Initializing a Simple MAPI Client.
    • For CMC, see Starting a CMC Session.
    • For MAPI, see Initializing MAPI and Initializing OLE for Use with MAPI.
    • For the Active Messaging Library, no explicit load step is necessary; simply instantiate one of the top-level objects, MAPI.Session or MAPI.Message.
  2. Log on to MAPI. IPM message classes should use the messaging client's session if available. IPC applications may need to use a specific profile they've created themselves.
    • For Simple MAPI, see Starting a Simple MAPI Session and related topics.
    • For CMC, see Starting a CMC Session.
    • For MAPI, see Logging On.
    • For the Active Messaging Library, see Session Handling.
  3. For MAPI only, access the default message store. See Opening a Folder.
  4. Create folders and receive folder mappings for your message class. For an IPC application the folders should be children of the message store's root folder, not of the IPM subtree. Include receive folder mappings for reports associated with your message class, if necessary. These steps can only be done using MAPI; if you have chosen a different interface, you can still write this code using MAPI and put it in your installation program.
    1. Open the root folder by calling the IMsgStore::OpenEntry method with a null entry identifier.
    2. Call the IMAPIFolder::CreateFolder method to create the folder.
    3. Call the IMsgStore::SetReceiveFolder method to establish a receive folder mapping for your message class. Several message classes can use the same receive folder; when processing incoming messages, you can restrict the folder's contents table on the PR_MESSAGE_CLASS property to isolate the messages you're interested in.
    4. Locate your folder. The most efficient way to find your folder once you've created it is a receive folder mapping. Even if you don't intend for the folder to receive messages, you can map it to a string that is not used as a message class. Named properties on the store object — the most obvious alternative — are not always supported by message store providers, and MAPI does not define a range of message store properties for application use.
  5. Open the send and receive folders for your message class.
    • For Simple MAPI, this step is not necessary. Simply specify the message class in your call to the MAPIFindNext function.
    • For CMC, this step is not necessary. Simply specify the message class in your call to the cmc_list function.
    • For MAPI, see Opening a Folder, and note the following.

      To open the receive folder:

    1. Call the IMsgStore::GetReceiveFolder method.
    2. Pass the entry identifier returned to the IMsgStore::OpenEntry method.

      To open the Outbox (send folder) for IPM only:

    3. Call the message store's IMAPIProp::GetProps method to retrieve the PR_IPM_OUTBOX_ENTRYID property.
    4. Pass the entry identifier to the IMsgStore::OpenEntry method.
    • For the Active Messaging Library, see Accessing Folders and InfoStores Collection Object.
  6. Send outgoing messages.

    Remember to handle the disposition of submitted messages. IPM message classes should honor common IPM client options for disposition of sent messages and the message store's PR_IPM_SENTMAIL_ENTRYID property.

    • For MAPI, see Processing a Sent Message and related topics.
    • For Simple MAPI, see Sending Messages with Simple MAPI.
    • For CMC, see Sending Messages with CMC.
    • For the Active Messaging Library, see Creating and Sending a Message.
  7. Handle incoming messages.
    • For Simple MAPI, call the MAPIFindNext function in a loop, specifying your message class.
    • For CMC, call the cmc_list and cmc_read functions in a loop, specifying your message class to cmc_read.
    • For MAPI, use the following steps:
    1. Open the contents table on the receive folder, using the IMAPIContainer::GetContentsTable method.
    2. Register for notification of new mail, using the IMsgStore::Advise method, the fnevNewMail event, and a null entry identifier. Do this before retrieving any messages to avoid a race condition that would result in missing messages.
    3. Create a property restriction to match PR_MESSAGE_CLASS with your message class and apply it to the contents table by calling IMAPITable::Restrict. Consider also limiting your contents table view to unread messages by creating a bitmask restriction with the MSGFLAG_UNREAD flag as the mask for the PR_MESSAGE_FLAGS property. See About Restrictions.
    4. Retrieve all the messages from the table, using the HrQueryAllRows function or the IMAPITable::QueryRows method, and process them.
    5. Rely on new mail notifications to advise you of further incoming messages. Your notification handler should check the lpszMessageClass member of the NEWMAIL_NOTIFICATION structure and ignore any messages that are not of your class.
    • For the Active Messaging Library, access the Messages collection of your receive folder, and use the GetFirst and GetNext methods to retrieve the messages.
  8. For each user of your application, make the .EXE file and any auxiliary files available.

About Sample Source Code

See the following topic:

Sample Timecard Application


Creating and Configuring a Profile

See Message Services and Profiles for more information about creating a profile using MAPI, adding message services to it and configuring them, and establishing certain default settings in the profile.

Design Tasks

  1. Understand what message services your profile requires, and whether you wish to give your user any choice of services.
  2. Choose your tool. There are several tools available for creating profiles. Alternatives include:
    • Not creating one and using the messaging client's profile. This is usually the best choice for interpersonal (IPM) applications, especially if you want to use the same message store as the messaging client.
    • Using the Profile Wizard to create a profile and having your user select message services interactively. For this technique to succeed, the services you require must all support wizard-based configuration, and your application must tolerate uncertainty in its configuration. See Creating a Profile with the Profile Wizard.
    • Using the NEWPROF.EXE utility and a template contained in a .PRF file to create a profile from a setup program or batch environment, or by spawning the utility from your own program. See Creating a Profile with NEWPROF.
    • Writing C or C++ code to create a profile. This is often the best choice for a noninteractive application which requires a specific set of message services. See Creating a Profile with Custom Code.
  3. Understand in what order to add services. Following are guidelines for ordering service providers. These guidelines will occasionally conflict; when they do, you will have to write C or C++ code to configure one or more of the provider orders. You can use the Delivery and Addressing pages of the Mail and Fax control panel applet to inspect a profile you have created and see if the providers have been ordered as you expected.
    • Default message store. The first message store added to a profile which is capable of being the default store becomes the default store. Ordinarily, the service you intend to contain the default store should be listed first. See IMAPISession::SetDefaultStore.
    • Personal address book (PAB), default directory, and address book search order. The PAB, if not set explicitly, is the first container that is writeable and can contain names (according to its PR_CONTAINER_FLAGS property). The default directory is the first container in the hierarchy that contains names and is not the PAB (unless the PAB is the only container that can contain names). The default search path is the PAB, followed by each directory that is of display type DT_GLOBAL, has names, and does not have the AB_NOT_DEFAULT flag set in PR_CONTAINER_FLAGS. If there are no directories of type DT_GLOBAL, the default search path is just the PAB and the default directory. See Resolving a Name, IAddrBook::SetPAB, and IAddrBook::SetSearchPath.
    • Transport order. If the transport order is not explicitly set, MAPI services transports in the same order they were added to the profile, except that transports which set the STATUS_XP_PREFER_LAST flag are serviced last. The transport order is unimportant unless your profile contains two or more transports which handle the same e-mail address type. See IMsgServiceAdmin::MsgServiceTransportOrder.

If your application must run unattended, perhaps as a background application or a Windows NT service, some special cautions apply. See Writing an Automated Client and Windows NT Service Client Applications.

If your application requires a specific profile other than the default profile, you must save its name in your own configuration database or use a specific naming convention. MAPI does not expose any profile attributes other than the name and default flag in the profile table, and the default profile flag is reserved for the messaging client and related IPM applications.

Implementation Tasks

To create a .PRF file for use with the NEWPROF.EXE utility
  1. Assemble information from existing .PRF files. For each service you plan to use, copy the section that lists the name, type, and property identifier for each configuration property. The section must have the same name as the service. Services implemented by Microsoft are listed in Section 4 of the DEFAULT.PRF file that is installed with MAPI.
  2. Place the profile name in the ProfileName= line of the [General] section.
  3. Create the [Service List] section, in Section 2 of the file. In this section, list each service you require and the name of the section that contains its configuration properties. Refer to the earlier guidelines to establish the order of services.
  4. For each service listed in the [Service List] section, create a section that lists the value for each configuration property; the section must have the same name as the service. This information appears in Section 3 of the file.
  5. Invoke the utility. On 32-bit operating systems, it can be run from a command line or batch file. On 16-bit Windows, NEWPROF.EXE cannot be run from an MS-DOS shell; it can be run by a Windows-based setup script, by the Run command on the File menu in Program Manager or File Manager, or by the WinExec system call. It takes command line parameters as follows:
    • -P descriptor-file-path

      An absolute path to the .PRF file. The default value is DEFAULT.PRF in the Windows directory.

    • -S

      If this option is present, NEWPROF.EXE displays a logging window showing what is being executed and any errors it encounters. By default no window is displayed.

    • -X

      If this option is present, NEWPROF.EXE immediately creates the profile. By default, it waits until the user chooses the Execute button in its window. This option is required if NEWPROF.EXE is to run without displaying its window.

    • -Z

      If this option is present, NEWPROF.EXE displays error messages and other debugging information in its window. By default this information is not displayed.

Note References to Sections 1, 2, 3, and 4 in the preceding procedure refer to comments in the DEFAULT.PRF file distributed with the Platform SDK.

To write custom C or C++ code to create a profile
  1. Read the header file for each service. Understand what properties you need to configure and what values you will use.
  2. Call the MAPIAdminProfiles function to obtain an IProfAdmin interface. Call the CreateProfile method to create your profile, and the AdminServices method to obtain an IMsgServiceAdmin interface.
  3. Add message services to the profile. Refer to the previous guidelines for the order you should use. For each service, use the IMsgServiceAdmin interface to:
    1. Call the CreateMsgService method.
    2. Obtain the MAPIUID structure of the service you just created.
    3. Call the GetMsgServiceTable method to obtain an IMAPITable interface.
    4. Call the HrQueryAllRows function to retrieve all rows from the table.
    5. Get the PR_SERVICE_UID column from the last row. This is the MAPIUID structure of the last service added. You may wish to check with an assertion that other properties of the service are as you expect.
    6. Call the ConfigureMsgService method, passing the MAPIUID structure of the service you just created and a property value array with its configuration properties.
  4. If you must make configuration calls that require an IMAPISession interface, such as IMAPISession::SetDefaultStore, IAddrBook::SetPAB, or IAddrBook::SetABSearchPath, pass the MAPI_NO_MAIL flag to the MAPILogonEx function.
  5. To make your profile temporary, call the IProfAdmin::DeleteProfile method immediately after logging on to the profile. It will be deleted after you log off, and will not be visible to other applications in the meantime.

About Sample Source Code

None available at this time.


Incorporating Formatted Text and Attachments

A client application can send or receive a message that includes formatted text and attachments. Clients that want to work with formatted text must use the MAPI client interface. CMC, Simple MAPI, and the Active Messaging Library do not support formatted text in messages.

Design Tasks

  1. Decide on a mechanism for displaying formatted text. You can use the Rich Text Format (RTF) supported by Microsoft or your own customized format. See Formatted Text in MAPI.
  2. Decide on the types of attachments that your client will handle. See Attachments.
  3. Decide if and how your client will activate and save its attachments. See Creating a Message Attachment.

Implementation Tasks

To send a message with formatted text
  1. Call the IMAPIProp::OpenProperty method to open the PR_RTF_COMPRESSED property, setting both the MAPI_CREATE and MAPI_MODIFY flags. MAPI_CREATE ensures that any new data replaces any old data and MAPI_MODIFY enables your client to make those replacements.
  2. Call the WrapCompressedRTFStream function, passing STORE_UNCOMPRESSED_RTF if the message store sets the STORE_UNCOMPRESSED_RTF bit in its PR_STORE_SUPPORT_MASK property, to get an uncompressed version of the PR_RTF_COMPRESSED stream returned from OpenProperty.
  3. Write the message text data to the uncompressed stream returned from WrapCompressedRTFStream.
  4. If the message data is an attachment, write the character token "\objattph" followed by a space to the stream instead of the attachment.
  5. Set the PR_RENDERING_POSITION property of the attachment to a value that will increase with each attachment. For example, the first attachment could be assigned 1 as its PR_RENDERING_POSITION, the second one 2, and so on.
  6. Commit and release both the uncompressed and compressed streams.
  7. If the message store does not support RTF as indicated by the absence of the STORE_RTF_OK setting in the PR_STORE_SUPPORT_MASK property, call the RTFSync function and pass the RTF_SYNC_RTF_CHANGED flag.

For more information, see Supporting Formatted Text in Outgoing Messages: Client Responsibilities.

To read a message with formatted text
  1. Call RTFSync to synchronize the message text with the formatting if the message store is not RTF-aware and the PR_RTF_IN_SYNC property is missing or set to FALSE. The RTF_SYNC_BODY_CHANGED flag should be passed in the ulFlags parameter. Clients working with RTF-aware message stores need not make the RTFSync call because the message store takes care of it.
  2. Call IMAPIProp::SaveChanges if the message has been updated.
  3. Call IMAPIProp::OpenProperty to open the PR_RTF_COMPRESSED property.
  4. Call the WrapCompressedRTFStream function, passing the STORE_UNCOMPRESSED_RTF flag if the message store sets the STORE_UNCOMPRESSED_RTF flag in its PR_STORE_SUPPORT_MASK property, to create an uncompressed version of the compressed RTF data.
  5. Display the uncompressed RTF data.

If there are attachments in the message, perform the following tasks in addition to the preceding steps:

  1. Before reading from the uncompressed RTF stream, sort the message's attachment table on the value of the PR_RENDERING_POSITION property. The attachments will now be in order by how they appear in the message.
  2. As your client scans through the RTF stream, check for the token "\objattph". The character following the token is the place to put the next attachment from the sorted table. Handle attachments that have set their PR_RENDERING_POSITION property to -1 separately.

For more information, see Supporting Formatted Text in Incoming Messages: Client Responsibilities.

About Sample Source Code

See the following topic:

Sample RTF Utility


Finding a Message in a Message Store

There are various tasks related to finding a message in a message store. The tasks are different, depending on the client interface you are using for your client and the message store. Some message stores support searching; others do not. Create a prototype to determine whether or not a particular search strategy will work.

If the message store supports searches, your client can use a search-results folder to locate messages. Clients written with the MAPI client interface can either create a new search-results folder or use a pre-existing one. Clients written with the Active Messaging Library must use a pre-existing search-results folder.

If the message store does not support searches, your client will have to traverse the message store hierarchy, looking through each folder for the target message rather than using search criteria.

Specifically, this topic explains how to:

  • Create a search-results folder using the MAPI client interface.
  • Locate an existing search-results folder using the Active Messaging Library.
  • Perform a search in a searchable message store using the MAPI client interface.

Design Tasks

  1. Determine whether or not the message store supports searches, meaning the ability to create search-results folders. Clients using message stores that support searches can use a search-results folder to find a message; clients using non-searchable message stores must traverse the folder hierarchy.
  2. For clients using message stores that support searches, determine whether or not the message store supports the type of restrictions you will be imposing. For example, if you want to use a property restriction, make sure that the message store supports the specific property.

Implementation Tasks

  1. Retrieve the PR_STORE_SUPPORT_MASK property from the message store by calling its IMAPIProp::GetProps method. If the STORE_SEARCH_OK flag is set, proceed. If this flag is not set, there are two choices:
    • Fail because the message store does not support searches.
    • Attempt the alternate strategy of enumerating the message store hierarchy.
  2. Create a search-results folder if possible. See the following procedure.
  3. If creating a search-results folder is not possible, locate an existing search-results folder. MAPI creates a default search-results folder called Search Root when it initializes a message store. Creating search-results folders is not allowed if you are using the Active Messaging Library. See the following procedure.
  4. Build a restriction that reflects your search criteria. See About Restrictions. If you are searching on a named property, call the IMAPIProp::GetIDsFromNames method to create a searchable property tag from the name.
  5. Start the search by calling the search-results folder's IMAPIContainer::SetSearchCriteria method. Pass the BACKGROUND_SEARCH or FOREGROUND_SEARCH flag as appropriate, the restriction, and the entry identifier of the folder in which to search.
  6. Retrieve the search results by opening the search-results folder's contents table and querying the rows. You can process this incrementally or wait for an fnevSearchComplete notification from the message store.

To create a search-results folder using the MAPI client interface
  1. Locate and open the target message store. See Opening a Message Store or Opening the Default Message Store.
  2. Retrieve the message store's PR_FINDER_ENTRYID property — the entry identifier of the root search-results folder.
  3. Open the root search-results folder by calling IMsgStore::OpenEntry with the entry identifier from the PR_FINDER_ENTRYID property.
  4. Create a new folder in the root search-result folder by calling the root folder's IMAPIFolder::CreateFolder method. Set the ulFolderType parameter to FOLDER_SEARCH. See Search-Results Folders.

To locate an existing search-results folder using the Active Messaging Library
  1. Locate and open the target message store using the Session.InfoStores collection. An InfoStore object provides access to the root folder for a message store.
  2. Retrieve the folder's FolderID property to identify its parent folder and pass this identifier in a call to Session.GetFolder to open the parent folder.
  3. Work up through the folder hierarchy by repeating the previous step until the FolderID property is the same in two sequential iterations. When this occurs, you will be at the root folder of the message store.
  4. Retrieve the Folders collection and browse for the folder whose name is Search Root. MAPI always creates a folder by that name when it initializes a message store.
  5. Retrieve the root search-results folder's Folders collection and browse for your own search-results folder by name.

To locate an existing search-results folder using the MAPI client interface
  1. Locate and open the target message store. See Opening a Message Store or Opening the Default Message Store.
  2. Retrieve the message store's PR_FINDER_ENTRYID property — the entry identifier of the root search-results folder.
  3. Open the root search-results folder by calling IMsgStore::OpenEntry with the entry identifier from the PR_FINDER_ENTRYID property.
  4. Access the folder's hierarchy table by calling IMAPIFolder::GetHierarchyTable.
  5. Look for a row in the table that has a PR_FOLDER_TYPE column set to FOLDER_SEARCH and a PR_DISPLAY_NAME column set to Search Root. MAPI always creates a folder by that name when it initializes a message store.

About Sample Source Code

See the following topic:

Sample Messaging Hook Provider


Using Message Filtering to Manage Messages

The MAPI spooler makes calls to two different types of extensions by which code can be inserted in the message transmission process. These extensions — known as preprocessors and spooler hooks — can be used for a wide variety of purposes including altering the recipient list or content of an outbound message, archiving outbound messages in local storage or on a central server, directing inbound messages to a particular folder based on arbitrary criteria, and responding automatically to inbound messages.

Design Tasks

  1. Decide whether to use a preprocessor or a spooler hook.

    A preprocessor is called for outbound messages only. It may choose to be called for all messages, or for messages that have recipients of a particular type. Those recipients can be selected based on the address type (PR_ADDRTYPE), on the MAPIUID which qualifies the recipient's entry identifier, or both. See IMAPISupport::RegisterPreprocessor.

    A preprocessor can create new messages based on the input message, returning them through its lpppMessage parameter. In no case should the input message be placed in the lpppMessage parameter. If a preprocessor does not want the input message to be sent, it should delete all the recipients and set the PR_DELETE_AFTER_SUBMIT property; the input message should not be deleted using message store calls.

    A spooler hook may choose to be called for all inbound messages, all outbound messages, or both, by setting the HOOK_INBOUND flag, the HOOK_OUTBOUND flag, or both in its PR_RESOURCE_FLAGS property on the provider profile section in MAPISVC.INF. See File Format of MAPISVC.INF.

    To delete an inbound or outbound message, a hook should set the HOOK_DELETE flag in its lpulFlags parameter. It should not use message store calls to delete the message presented to it through its interface; it may use message store calls to create, modify, or delete other messages. A hook can prevent processing of a message by other hooks, including the default hook that processes receive folder settings, by setting the HOOK_CANCEL flag in lpulFlags.

    When working with a tightly coupled message store and transport, the store itself can transmit a message that is not destined for any spooler-based transports. Whether preprocessors and hooks are called in this situation depends upon the message store implementation. Microsoft Exchange Server, for example, calls preprocessors on outbound messages but does not call either inbound or outbound spooler hooks. See Sending Messages with MAPI.

    On an outbound message, hooks and preprocessors participate in a complicated sequence of events. The following steps involve hooks and preprocessors.

    1. The PreprocessMessage entry point of each preprocessor is called before any transport provider handles the message. It can update the recipient list, alter message content, or even create additional messages. The order in which preprocessors are called is the same as the order in which the transports that registered them are called to handle outbound messages. See Creating and Configuring a Profile.
    2. Transport providers are called to transmit the message. If any transport defers message processing, no hooks are called until the deferred processing is complete.
    3. The RemovePreprocessInfo entry point of each preprocessor is called after all transports have handled the message.
    4. The ISpoolerHook::OutboundMsgHook method is called for each hook that sets the HOOK_OUTBOUND flag in the PR_RESOURCE_FLAGS property. The order in which hooks are called is the same as the order in which they were installed in the profile; it does not follow the transport order because a hook does not necessarily have an associated transport provider.

    For inbound messages, preprocessors are not called. Hooks are called as follows:

    1. The receiving transport provider completes its work.
    2. The ISpoolerHook::InboundMsgHook method is called for each hook that sets the HOOK_INBOUND flag in the PR_RESOURCE_FLAGS property. The order in which hooks are called is the same as the order in which they were installed in the profile; it does not follow the transport order because a hook does not have an associated transport provider.
    3. For inbound messages, the receive folder assignment is honored only if a hook has not moved the message to another folder. Conceptually, the MAPI spooler implements an internal hook which is always called last and only if no previous hook returns the HOOK_CANCEL flag; it finds the receive folder based on the message's PR_MESSAGE_CLASS property and places the message in that folder. See IMsgStore::GetReceiveFolder.
  2. Define configuration parameters and understand how your hook or preprocessor is to be installed. A spooler hook is a distinct service provider type and is added to the user's profile as part of a message service, either alone or together with other related service providers. Any configuration parameters are normally stored in the profile and edited using the property pages for the message service. A preprocessor is not a distinct service provider type; it must be registered by a transport provider. If necessary, a minimal transport provider can be created for this purpose alone.

Implementation Tasks

To implement a preprocessor
  • Create a DLL containing the PreprocessMessage and RemovePreprocessInfo entry points. It is strongly recommended, though not required, that all the code and entry points listed here be implemented in the same DLL; this minimizes the delay in loading MAPI applications.
  • Call the IMAPISupport::RegisterPreprocessor method in a transport provider.
  • Create a transport provider entry point, and the remainder of a minimal transport, if there is no existing transport. The minimal transport should initialize as recommended in the topic Required Functionality for Transport Providers. In response to the IXPLogon::AddressTypes call, the transport provider should return a single zero-length string in lpppszAdrTypeArray and NULL in lpppUIDArray.
  • Create a MAPISVC.INF fragment for the transport provider and the message service that contains it. See Implementing a Message Service.
  • Optionally, but strongly recommended, create a message service entry point for configuration. See Implementing a Service Provider Entry Point Function.
  • Optionally, create an online Help file linked to your configuration property pages, wizard pages, or both, providing full details about all configuration options.
  • Optionally, create a header file for custom programmatic configuration by MAPI clients.
  • Optionally, create a service wizard entry point for interactive configuration by users. See Supporting Message Service Configuration and WIZARDENTRY.
  • Optionally, create a .PRF file detailing configuration properties for the message service. See Creating a Profile with NEWPROF.
To implement a spooler hook
  • Create a DLL containing the HPProviderInit entry point. It is strongly recommended, though not required, that all the code and entry points listed here be implemented in the same DLL; this minimizes the delay in loading MAPI applications. See Implementing a Service Provider Entry Point Function.
  • Create a MAPISVC.INF fragment for the hook provider and the message service that contains it. See Implementing a Message Service.
  • Optionally, but strongly recommended, create a message service entry point for configuration. See Implementing a Service Provider Entry Point Function.
  • Optionally, create a header file for custom programmatic configuration by MAPI clients.
  • Optionally, create a service wizard entry point for interactive configuration by users. See Supporting Message Service Configuration and WIZARDENTRY.
  • Optionally, create an online Help file linked to your configuration property pages, wizard pages, or both, providing full details about all configuration options.
  • Optionally, create a .PRF file detailing configuration properties for the message service. See Creating a Profile with NEWPROF.

About Sample Source Code

See the following topics:

Sample Transport Provider

Sample Messaging Hook Provider


Finding Information About a User in the Address Book

You can find a user in the address book given a name, part of a name, or other information about the user; retrieve information from that entry; and search for several users at a time.

Design Tasks

  1. Decide whether you're searching the entire address book, one or more containers belonging to a specific message service, or a particular type of container such as a personal or global address list.
  2. Decide what properties are in your search criteria. The only property you can rely on searching with acceptable performance is PR_DISPLAY_NAME. If you want to use another property such as an account name, employee identification number, or organization name, you must experiment with the address book providers you expect to use to verify that searching on those properties is supported and the performance is acceptable.
  3. Understand whether or not the information you are given should identify each user uniquely. If it can be ambiguous — if it can match more than one entry in the address book — then decide whether your program should:
    • Prompt its user to choose the right entry.
    • Choose the right entry itself based on further information retrieved about each entry.
    • Fail.

Implementation Tasks

To search the entire address book by display name for one or more entries
  • Use the IAddrBook::ResolveName method. You can optionally request a dialog box that prompts the user to choose the correct entry in case the information you were given matches more than one entry.
To open the user's personal address book (PAB)
  1. Retrieve its entry identifier by calling the IAddrBook::GetPAB method.
  2. Call the IAddrBook::OpenEntry method passing the PAB's entry identifier.
To open a specific container other than the PAB
  1. Open the address book's root container by calling the IAddrBook::OpenEntry method with a NULL entry identifier. The root container is constructed by MAPI and contains the top-level containers of all the address book providers in the profile.
  2. Get the list of top-level containers by calling the IMAPIContainer::GetHierarchyTable method.
  3. If you want a specific container type such as the global address list, restrict the table on PR_DISPLAY_TYPE:
    1. Create a property restriction to match PR_DISPLAY_TYPE with the value for the particular type of container you want to open. For example, to open the global address book, build a property restriction that matches PR_DISPLAY_TYPE with the DT_GLOBAL value.
    2. Create an SPropTagArray including PR_ENTRYID, PR_DISPLAY_TYPE, and any other columns of interest.
    3. Call the HrQueryAllRows function passing your property tag array and restriction. Ordinarily, there will be a single global address list, but the call can return zero, one, or more rows depending on the address book providers in your profile. Be prepared to handle all these cases, not just one row.
    4. Call the IAddrBook::OpenEntry method with the PR_ENTRYID column from the row you want to open the container.
  4. If you want a container belonging to a specific address book provider, restrict the table on PR_AB_PROVIDER_ID:
    1. Create a property restriction to match PR_AB_PROVIDER_ID with the value that represents the target address book provider. You will find this property value in a header file created by the service provider. In the Platform SDK, for instance, the value for the flat file address book sample is SAB_PROVIDER_ID in SMPAB.H.
    2. Create an SPropTagArray structure including PR_ENTRYID, PR_AB_PROVIDER_ID, and any other columns of interest.
    3. Call the HrQueryAllRows function passing your property tag array and restriction. The call will return zero rows if the provider you want is not in the profile. It can return one or more rows depending on the provider's containers are organized, but it will only return the top-level rows.
    4. Call the IAddrBook::OpenEntry method with the PR_ENTRYID column from the row you want to open the container. If the container you want is not a top-level container, you will then have to navigate down through the latter's hierarchy table.
To search in a specific address book container
  1. Open its contents table by calling its GetContentsTable method.
  2. Use IMAPITable::FindRow, IMAPITable::SortTable, and IMAPITable::Restrict to search the contents table just as you can any MAPI table. See Table Positioning and About Restrictions. These methods are subject to limitations in the provider's implementation, and their speed is unpredictable; careful testing against any providers you expect to use is indispensible. In addition to the normal IMAPITable methods, there are two search techniques specific to address book containers:
    • Restriction on PR_ANR (ambiguous name resolution). Although formatted as an ordinary SPropertyRestriction structure, this restriction actually invokes a special display name matching algorithm based on separating the string you give it into words and prefix-matching those words against display names in the address book. See Implementing Name Resolution.
    • IABContainer::ResolveNames. This method does the same work as a PR_ANR restriction for multiple names, and can be much faster. Providers are not required to implement it, and generally do not unless it carries a significant performance benefit. It is not necessary to open the contents table in order to user this method.
  3. After applying any of the restriction methods listed above, call the IMAPITable::QueryRows method to retrieve any rows that match the restriction. You may get back zero, one, or more rows that match.
  4. Retrieve additional information for a single address book entry by calling the IAddrBook::OpenEntry method passing its entry identifier, then call GetProps on the resulting IMAPIProp interface. To retrieve additional properties for multiple address book entries, you can of course call OpenEntry for each one, but it is usually much more efficient to call the IAddrBook::PrepareRecips method. PrepareRecips requires an ADRLIST structure.


About MAPI Samples

The Platform SDK contains a variety of samples in C, C++, and Visual Basic. There are samples for different types of client applications and service providers. There are also several tools for accessing some of the basic MAPI objects.

To run any of the samples on a Windows NT platform, you must first set up the MAPI runtime system. Refer to the README.TXT that contains the release notes for the SDK.

For information about sample extensions to the Microsoft Exchange client, see About Samples in the Microsoft Exchange Client Extensions Programmer's Reference.

Note All executable names have "32" appended to them when built for 32-bit platforms. The routing client, for instance, is named ROUTE.EXE when built for 16-bit Windows, but ROUTE32.EXE when built for 32-bit Windows.

See the documentation for the Active Messaging Library and extending the Microsoft Exchange Client for information about related samples.


Sample Address Book

This sample supports a single read-only container with names read from a flat binary file containing display names and e-mail addresses. It supports one-off templates and all configuration options except the Profile Wizard.

Quick Info

Executable: | SMPAB.DLL
Directory for source code: | FLATFILE.AB
Written in: | C
Supports: | All platforms

Supported Features

  • Table restrictions

    The sample implements prefix match and ambiguous name resolution. It does not implement the full MAPI restriction language, and restrictions are supported only on the display name.

  • Details display table for messaging users
  • One-off addresses
  • Advanced search dialog box
  • IMAPIStatus interface

    This interface is partially supported; its IMAPIProp methods are delegated to the IPropData interface.

  • Interactive and programmatic configuration

Unsupported Features

  • Sorting
  • Distribution lists
  • Creating, deleting and modifying entries
  • Multivalued properties
  • Named properties
  • Distinguishing first and last name in display names


Sample CMC Client

This sample demonstrates the use of all CMC calls in a very simple messaging client. It can send and read messages, list the contents of the Inbox, and view the address book.

Quick Info

Executable: | CMCCLI.EXE
Directory for source code: | CMC.CLI
Written in: | C
Supports: | All platforms


Sample Custom Sendable Form

This sample demonstrates how to use a custom sendable form. It implements the MAPI form interfaces and a more elaborate message; each message represents a move in a game of checkers between two players.

Quick Info

Executable: | WCHECK.EXE
Directory for source code: | CHECKERS.FRM
Written in: | C++
Supports: | All platforms


Sample Form

This sample implements the MAPI form interfaces and a very simple message, containing only text and recipients. The form can be used by form-aware clients for sending and receiving messages of IPM.Note.Sample.Simple message class instead of standard send/read forms. It is a good basis for reuse in a more complicated form.

Quick Info

Executable: | SMPFRM.EXE
Directory for source code: | SIMPLE.FRM
Written in: | C++
Supports: | Win32 platforms only

Supported Features

  • Sending messages
  • Replying to and forwarding messages
  • Next, Previous
  • Saving and deleting messages

Unsupported Features

  • Attachments
  • Reply All, Post
  • Moving and copying messages
  • Printing


Sample Message Store

This sample uses directories as folders and OLE 2 docfiles as messages (with the MAPI message-on-storage utility). It supports all features required of a default message store. Neither its IMAPIProp nor its IMAPITable interfaces are native; they are provided by the message-on-storage facility and ITableData respectively.

Quick Info

Executable: | SMPMS.DLL
Directory for source code: | DOCFILE.MS
Written in: | C
Supports: | All platforms

Supported Features

  • Basic operations

    Reading, creating, modifying, and deleting messages; browsing, creating and deleting folders; submitting outbound messages to transports; and associating all types of attachments with messages. Multivalued properties are supported for all objects. The sample message store can be used as the default message store for a MAPI client.

  • Moving and copying messages and folders

    These operations are delegated to MAPI support functions unless an operation occurs entirely within one sample message store.

  • Event notification on tables
  • Thread safety

Unsupported Features

  • Named properties:

    IMAPIProp::GetNamesFromIds and GetIDsFromNames methods

  • Searches:

    IMAPIFolder::SetSearchCriteria method

  • Categorization of contents tables
  • Associated information:

    MAPI_ASSOCIATED and DEL_ASSOCIATED flags

  • IMAPIStatus interface
  • ServiceEntry interface for configuration
  • Other methods including IMAPIFolder::OpenProperty and IMsgStore::CopyTo


Sample Messaging Hook Provider

This sample processes inbound and outbound messages. It can archive sent and deleted messages into folders by month and year, place incoming messages into folders based on variable criteria, and automatically respond to incoming messages in Rich Text Format.

Quick Info

Executable: | SMH.DLL
Directory for source code: | MANAGER.SH
Written in: | C
Supports: | Win32 platforms only

Supported Features

  • Filtering of inbound messages
  • Archiving sent mail
  • Archiving deleted mail


Sample Profile Client

This sample creates and configures a profile using some of the Microsoft message services.

Quick Info

Executable: | MKPROF.EXE
Directory for source code: | PROFILE.CLI
Written in: | C++
Supports: | All platforms


Sample Remote Transport Provider

This sample uses named pipes to communicate with a server process running on Windows NT. It uses TNEF exclusively to encode message content. It supports all configuration options and the remote transport interfaces.

Quick Info

Executable: | XPWDSR.DLL
Directory for source code: | REMOTE.XP REMOTE.SRV (sample server)
Written in: | C++
Supports: | Win32 platforms only Windows NT only (sample server)

Supported Features

  • Slow-link connection to a remote host
  • Deferred delivery
  • Forced immediate connection and submission
  • Server-based messaging
  • TNEF to encapsulate all the message properties
  • IMAPIStatus interface for client access to transport status
  • Thread safety
  • Configuration dialog boxes
  • Generation of delivery and nondelivery reports
  • Profile Wizard for interactive profile configuration
  • WINDS address type
  • MAPI spooler marshalled remote connections


Sample Routing Client

This sample creates a message with an attached document and a simple linear route using MAPI. It can also send and read forms.

Quick Info

Executable: | ROUTE.EXE
Directory for source code: | ROUTE.CLI
Written in: | C
Supports: | All platforms


Sample RTF Utility

This sample sends a message with Rich Text Format content based on command line parameters.

Quick Info

Executable: | SNDRTF.EXE
Directory for source code: | SENDRTF.CLI
Written in: | C++
Supports: | Win32 platforms only


Sample Simple MAPI Client

This sample demonstrates the use of all Simple MAPI functions in a very simple messaging client. It can send and read messages, list the contents of the Inbox, and view the address book.

Quick Info

Executable: | SMPCLI.EXE
Directory for source code: | SIMPLE.CLI
Written in: | C
Supports: | All platforms


Sample Timecard Application

This sample demonstrates creating and sending messages with custom fields using the Active Messaging Library.

Quick Info

Executables: | TMCLI.EXE TMSRV.EXE
Directory for source code: | TIMECARD.CLI*
Written in: | Visual Basic 4.0
Supports: | All platforms

*This directory is located at ftp://ftp.microsoft.com/developr/mapi/samples/mfcapps/mfcapps.zip.


Sample Transport Provider

This sample uses files and directories to transmit and receive messages. It implements and registers a very simple preprocessor that appends a line of text to each outbound message. It illustrates how to split message content between TNEF and text. It also supports all configuration options (property sheets, wizard, and programmatic configuration) and message options. It does not support the remote transport interfaces.

Quick Info

Executable: | SMPXP.DLL
Directory for source code: | PEER.XP
Written in: | C
Supports: | All platforms

Supported Features

  • Basic features:

    Sending, receiving and polling for new messages

  • Interactive and programmatic configuration
  • IMAPIStatus interface except property setting
  • Thread safety
  • Event logging to a text file

    The file is automatically limited to a specified size. All transport sessions use the same file.

Unsupported Features

  • Asynchronous detection of incoming messages


About MAPI Tools

The MAPI documentation within the Platform SDK contains several tools to aid in installation and to access some of the basic MAPI objects. To run any of the tools on a Windows NT platform, you must first set up the MAPI runtime system. Refer to the README.TXT that contains the release notes for the SDK.


Address Book Viewer

The Address Book Viewer is a MAPI client application that displays the properties of address book containers, distribution lists, and messaging users and exercises the methods of the address book interfaces: IAddrBook, IABContainer, IDistList, and IMailUser. The Address Book Viewer is especially useful if you are:

  • Writing an address book provider.
  • Writing a client application that depends heavily on address book features and properties.
  • Debugging a client application or transport provider that works with a variety of address book providers.
  • Exploring differences in behaviors between address book providers.

Quick Info

Executable: | ABVIEW.EXE (16-bit platforms) ABVIEW32.EXE (32-bit platforms)
Directory for source code: | ABVIEW.CLI*
Written in: | C++ using Microsoft Foundation Classes (MFC)
Supports: | All platforms

*This directory is located at ftp://ftp.microsoft.com/developr/mapi/samples/mfcapps/mfcapps.zip.

List of Source Files

ABIMAGES.BMP: | Bitmaps used in the Address Book Viewer
ABVIEW.CPP | CAppWin class, main menu, and common code
ABVIEW.H | Common definitions
ABVIEW.ICO | Address Book Viewer application icon
ABVIEW.RC | Address Book Viewer resource script
ABVIEW16.DEF | Address Book Viewer 16-bit module definition file
MAKEFILE | Builds the 32-bit version of the Address Book Viewer
MAKEFILE.16 | Builds the 16-bit version of the Address Book Viewer
RESOURCE.H | Resource identifiers
TBLLIST.CPP | CTblList class, used for viewing IMAPITable data in a listbox
TBLLIST.H | CTblList class definitions


Building the Address Book Viewer

The Platform SDK includes a command-line makefile for use with the NMAKE utility. This makefile follows Platform SDK conventions and includes WIN32.MAK. The makefile can also be used as an external makefile from Microsoft Developer Studio.

To build the debugging version for Win32 platforms, type

nmake

To build the retail version for Win32 platforms, type

nmake NODEBUG=1

To build the debugging version for Win16 platforms, type

nmake -f makefile.16

To build the retail version for Win16 platforms, type

nmake -f makefile.16 NODEBUG=1


Installing the Address Book Viewer

To install the Address Book Viewer, place all of the following executable files either in the same directory or in one or more directories in your path. Several of these files are shared with the Message Store Viewer, another MAPI tool. If you are using a Win16 platform, you will need:

  • ABVIEW.EXE
  • PROPVU.DLL
  • TBLVU.DLL
  • XVPORT.DLL

If you are using a Win32 platform, you will need:

  • ABVIEW32.EXE
  • PROPVU32.DLL
  • TBLVU32.DLL
  • XVPORT.DLL

The DLL files support the display of specialized viewers. PROPVU and PROPVU32 are Property Viewers; they display the properties of address book objects and allow you to make calls to IMAPIProp methods. The Property Viewer appears as follows when used to show the properties of a messaging user:

TBLVU and TBLVU32 are platform-specific versions of the Table Viewer for displaying table data and invoking IMAPITable methods. For example, the Personal Address Book's one-off table appears as follows when displayed with the Table Viewer:

XVPORT.DLL is used by the Address Book Viewer to maintain a session history by displaying log data and saving that data to one or more files.


Using the Address Book Viewer

To use the Address Book Viewer, start ABVIEW.EXE or ABVIEW32.EXE, depending on your platform. The Address Book Viewer uses a series of dialog boxes driven by menu selections to display and prompt for information. If you are not already running a messaging client application such as Microsoft Exchange, the Address Book Viewer will first prompt you for the name of a profile. If you are running a messaging client, the Address Book Viewer will use the profile that the client is currently using.

If you are running the Address Book Viewer for the first time, select Configure from the Help menu and enter the DLL names of the Table Viewer and Property Viewer. Depending on your target platform, enter TBLVU32.DLL or TBLVU.DLL in the field labeled "Table Vu DLL" and PROPVU32.DLL or PROPVU.DLL in the field labeled "Property Vu DLL." All of the other fields may be left blank.

After this initial configuration, you can use any of the three Address Book Viewer menus. There is a File menu to start and end MAPI session and a Help menu to display information about the Address Book Viewer and to perform configuration. The primary menu is the Address Book menu. With the selections from the Address Book menu, you can display the properties of containers, messaging users, and distribution lists and invoke several methods of the IAddrBook interface.

The menus of the Address Book Viewer appear as follows:

When you use the File menu to log on to MAPI, the Address Book Viewer calls MAPILogonEx to establish a MAPI session. If you're debugging an address book provider, its ABProviderInit function and IABProvider::Logon method are called at this point. The Address Book Viewer also calls IMAPISession::OpenAddressBook to make the address book accessible. When you log off, the Address Book Viewer releases its pointer to the address book, calls IMAPISession::Logoff, and then releases its session pointer.

The Address Book menu provides selections for displaying information about the root container, for displaying messaging user or distribution list properties, for building a recipient list using one, two, or three wells, and for invoking the following IAddrBook methods:

  • ResolveName
  • CreateOneOff
  • NewEntry

For more information about the Address Book menu selections, see one of the following topics:

Displaying the Root Container

Displaying the Properties of Container Entries

Building a Recipient List

Calling IAddrBook Methods

The Help menu provides two selections: About and Config. The About selection provides summary information about the Address Book Viewer including its full name and version. The Config selection displays a dialog box that you can use to configure the Address Book Viewer. For more information about how to configure the Address Book Viewer, see Configuring the Address Book Viewer.


Displaying the Root Container

To display the top-level address book container, select AB Root Container from the Address Book Viewer's Address Book menu. The root container's browsing dialog box appears, showing the container's hierarchy table in the left pane and a set of buttons and check boxes on the right:

Keep in mind that the preceding dialog box represents a hierarchy table of containers in a session that is using the Microsoft Exchange Server. You will see containers displayed in the table that are applicable to your profile and your session.

The Performance and Test buttons are disabled because the Address Book Viewer was not configured with either a performance or test DLL. The hierarchy table display includes containers from all registered address book providers in the current path. The containers that have subcontainers are marked with a plus sign, as is the Microsoft entry in the prior example. By double-clicking one of the containers in the hierarchy table, you can display its contents table and choose options that affect the selected container or one of its entries.

The buttons and check boxes are divided into two groups. The first group, labeled On "this", operates on the container being browsed; the second group, labeled On Selection, operates on the item selected in the browse pane. The following table describes the functionality provided by the controls in the first group:

Control | Description
Set as target | Makes this container the target for the Add to PAB command.
Table Vu | Displays the Table Viewer for browsing this container's tables and manipulating their views with IMAPITable methods.
Property Vu | Displays the Property Viewer for browsing this container's properties and invoking IMAPIProp methods.
Performance | Currently unsupported.
Test | Currently unsupported.
Details Tbl | Displays the Table Viewer for the container's details table. You must select a display property on which to sort the view. PR_YPOS is the typical choice. This table controls the appearance of the details dialog box; it can be informative to compare it with the details dialog box itself using the Details button.
One-Off Tbl | Displays the Table Viewer for the container's one-off table.
IDs / Names | Lists this container's mapping of property names to identifiers in its IMAPIProp interface.
Names / IDs | Lists this container's mapping of property identifiers to names in its IMAPIProp interface.
Get Props() | Displays property values retrieved from this container's IMAPIProp interface.
GetPropList() | Displays property tags retrieved from this container's IMAPIProp interface.
Details | Calls IAddrBook::Details for this container. It can be instructive to compare this dialog box with the display table used to generate it. Use the Details Tbl button for this comparison.
Add to PAB | Adds this container to the Personal Address Book, an operation that typically is not allowed.
Resolve Names | Prompts for a search string and then attempts to resolve the name in the container using IABContainer::ResolveNames.

In the On Selection group, the Address Book Viewer includes the following controls:

Control | Description
Set as target | Makes this item the target for the Add to PAB command.
Open Entry | Displays a dialog box for browsing the selected item, either a container, messaging user, or distribution list.
Test | Performs debugging, if you have configured the Address Book Viewer with a test DLL.
CONVENIENT_DEPTH | When checked, sets the ulFlags parameter of IMAPIContainer::GetHierarchyTable to CONVENIENT_DEPTH, filling the hierarchy table with containers from multiple levels. When not checked, the hierarchy table displays only the container's immediate child containers.
From Table | Displays the properties listed in the container's contents table for this item.
GetProps() | Displays property values retrieved from this item's IMAPIProp interface.
GetPropList() | Displays property tags retrieved from this item's IMAPIProp interface.
Details | Calls IAddrBook::Details for the selected item.
Add to PAB | Adds this item to the Personal Address Book.


Configuring the Address Book Viewer

To configure the Address Book Viewer, select Config. The following dialog box is displayed:

There are three parts to the configuration dialog box. The first part allows you to specify the names of DLLs that the Address Book Viewer can use for additional functionality. You can specify the name of a DLL to support table views, property views, performance, or testing. None of these DLLs are required. However, because displaying tables are an integrated part of the Address Book Viewer, if you do not specify a Table Viewer DLL, a default one is loaded. The Address Book Viewer attempts to load TBLVU.DLL for 16-bit platforms and TBLVU32.DLL for 32-bit platforms. There are no default options for the other DLLs.

The second part is labeled ABView Test Options and contains three check boxes. If you select Allow option to set a target container (AddToPab), the AddToPab button will appear on all future dialog boxes relating to specific containers. If you choose Allow option to select Hierarchy or Contents table, the Address Book Viewer will prompt you each time you display a container.

The third part is labeled MAPI Flags and contains check boxes for setting the ulFlags parameter for the following method calls:

  • Set ulFlags to MAPI_MODIFY in all OpenEntry calls.
  • Set ulFlags to MAPI_UNICODE in all IMAPIProp::GetProps calls.
  • Set ulFlags to MAPI_UNICODE in all MAPI method calls.
  • Set ulFlags to CONVENIENT_DEPTH in all IABContainer::GetHierarchyTable calls.


Displaying the Properties of Container Entries

To display messaging user or distribution list properties, choose Address 0 Well from the Address Book menu. The Address Book Viewer displays relevant information about each of the entries in the selected container, as shown in the following dialog box:

From this dialog box, you can choose to view the properties of a particular entry. Either specify a target entry or select one from the list.


Building a Recipient List

You can use the Address Book Viewer to create a recipient list that is made up of one, two, or three types of recipients. Every recipient list has at least one direct recipient, entered on the To line of an outgoing message form. In addition, there can be carbon copy (CC) or blind carbon copy (BCC) recipients. Depending on the types of recipients that you'd like to include, select one of the following from the Address Book menu:

Address Book Menu Selection | Description
Address 1 Well | Creates a recipient list with direct recipients only.
Address 2 Well | Creates a recipient list with direct and carbon copy recipients.
Address 3 Well | Creates a recipient list with direct, carbon copy, and blind carbon copy recipients.

As an example, the following dialog box is generated when you select Address 2 Well:

Notice that in addition to the standard dialog box buttons and the recipient wells, there are three other buttons: New, Properties, and Find. The New button allows you to create a new entry from one of the templates offered by the container and optionally add the new entry to the Personal Address Book. The Properties button displays a property sheet using the Property Viewer. The Find button launches a search dialog box, allowing you to specify simple or more complex search criteria for locating container entries.

As you can see in the first of the two dialog boxes that follow, you can search in a forward or backward direction or use a bookmark. You can also specify a restriction as a filter. When you select the Build Restriction button, the second dialog box appears, prompting you to replace None for the restriction type with a valid type and related information. The dialog box used that you use to enter restriction information is also used in the Message Store Viewer.


Calling IAddrBook Methods

You can invoke most of the methods of the integrated IAddrBook interface from one or more of the dialog boxes included with the Address Book Viewer. The following table lists the most common ways of exercising IAddrBook methods with the Address Book Viewer.

To call | Procedure
IAddrBook::Address | From the Address Book menu, select one of the following: Address 0 Well Address 1 Well Address 2 Well Address 3 Well
IAddrBook::CreateOneOff | From the Address Book menu, select CreateOneOff.
IAddrBook::Details | From the AB Root Container dialog box, select Details.
IAddrBook::GetOneOffTable | From the AB Root Container dialog box, select One-Off Tbl.
IAddrBook::GetPAB | From any of the dialog boxes that contain it, select Add to PAB.
IAddrBook::NewEntry | From the Address Book menu, select one of the following: NewEntry Address 1 Well Address 2 Well Address 3 Well
IAddrBook::OpenEntry | From the AB Root Container dialog box, select Open Entry or select the Address List dialog box displayed as part of the name resolution operation.
IAddrBook::PrepareRecips | From the Address List dialog box, select PrepareRecips.
IAddrBook::RecipOptions | From the Address List dialog box displayed as part of the name resolution process, select RecipOptions.
IAddrBook::ResolveName | Select one of the following: From the AB Root Container dialog box, select ResolveName(s). From the Address Book menu, select Resolve Name.

Many of these operations cause additional dialog boxes to be displayed, prompting for related information. For example, when you select Resolve Name from the Address Book menu, a dialog box is displayed into which you must enter the name to be resolved. Depending on the success of the operation, the Address Book Viewer either displays a Check Names dialog box or an Address List dialog box. Check Names allows you to select an entry from the container or to find a more appropriate entry from a different container. When the name is resolved, the Address List dialog allows you to view recipient properties or invoke IAddrBook::OpenEntry, IAddrBook::PrepareRecips, or IAddrBook::RecipOptions.


Message Store Viewer

This tool displays message, folder, and message store properties in raw form, and exercises nearly all methods on message store provider interfaces. It is useful both for exercising message store providers and for understanding what properties are present on objects in a store.

Quick Info

Executable: | MDBVU.EXE
Directory for source code: | MDBVIEW.CLI*
Written in: | C++ using Microsoft Foundation Classes (MFC)
Supports: | All platforms

*This directory is located at ftp://ftp.microsoft.com/developr/mapi/samples/mfcapps/mfcapps.zip.


Property Viewer

This tool displays the properties directly accessible through an IMAPIProp interface implementation, and exercises all methods of the interface.

Quick Info

Executable: | PROPVU.DLL
Directory for source code: | PROPVU.CLI*
Written in: | C++ using Microsoft Foundation Classes (MFC)
Supports: | All platforms

*This directory is located at ftp://ftp.microsoft.com/developr/mapi/samples/mfcapps/mfcapps.zip.


Simple MAPI Stress Mailer

This tool generates message traffic using Simple MAPI. It can send a message any number of times, at any interval, with message text and attachments of any size.

Quick Info

Executable: | SEND.EXE
Directory for source code: | SEND.CLI*
Written in: | C++ using Microsoft Foundation Classes (MFC)
Supports: | All platforms

*This directory is located at ftp://ftp.microsoft.com/developr/mapi/samples/mfcapps/mfcapps.zip.


Status Table Viewer

This tool displays the MAPI status table in raw form and exercises provider IMAPIStatus interfaces.

Quick Info

Executable: | STATVU.DLL
Directory for source code: | STATUSVU.CLI*
Written in: | C++ using Microsoft Foundation Classes (MFC)
Supports: | All platforms

*This directory is located at ftp://ftp.microsoft.com/developr/mapi/samples/mfcapps/mfcapps.zip.


Table Viewer

This tool displays the properties directly accessible through an IMAPITable interface implementation, and exercises all methods of the interface.

Quick Info

Executable: | TBLVU.DLL
Directory for source code: | TABLEVU.CLI*
Written in: | C++ using Microsoft Foundation Classes (MFC)
Supports: | All platforms

*This directory is located at ftp://ftp.microsoft.com/developr/mapi/samples/mfcapps/mfcapps.zip.


Concepts and Architecture

As business becomes more competitive, the success of an organization increasingly depends on how quickly, smoothly, and efficiently people within that organization work together. The key to a successful organization is how well that organization manages and distributes information. Networking is an important part of teamwork because it enables fast and efficient information exchange. But networking is only part of the solution; organizations must also keep track of the information and manage its distribution. Electronic messaging systems provide these capabilities.

Electronic messaging has become critically important to enterprise computing. In fact, many organizations are looking to their electronic messaging systems to take on the role of a central communications backbone, used not only for electronic-mail (e-mail) messages, but to integrate all types of information. Electronic messaging provides a way for users in organizations to retrieve information from a variety of sources, to exchange information automatically, and to store, filter, and organize the information locally or across a network.

Today, powerful enterprise-wide workgroup applications that manage group scheduling, forms routing, order processing, and project management are built on electronic messaging systems. Hundreds of different messaging systems are offered by different vendors, and a wide range of applications have been built to use them. But each of these messaging systems has a different programming interface, making an extensive development effort necessary to enable an application to interact with more than one system.

To solve this problem, Microsoft, along with more than 100 independent software vendors (ISVs), messaging system suppliers, corporate developers, and consultants from around the world, has created the Messaging Application Programming Interface (MAPI). MAPI is a messaging architecture that enables multiple applications to interact with multiple messaging systems seamlessly across a variety of hardware platforms.

MAPI is made up of a set of common application programming interfaces and a dynamic-link library (DLL) component. The interfaces are used to create and access diverse messaging applications and messaging systems, offering a uniform environment for development and use and providing true independence for both. The DLL contains the MAPI subsystem, which manages the interaction between front-end messaging applications and back-end messaging systems and provides a common user interface for frequent tasks. The MAPI subsystem acts as a central clearinghouse to unify the various messaging systems and shield clients from their differences.


About MAPI Features

MAPI has several key features that enable it to provide a consistent way for developers to work with and use different messaging systems in a seamless fashion. These features are:

  • An open programming interface
  • A dual-purpose interface, separated into two independent parts
  • A comprehensive interface
  • Integration with the operating system
  • Support for industry standards

Because MAPI is an open programming interface, it provides services in a generic way, allowing its users to add any necessary customization now and in the future. The users of the MAPI interface include all levels and types of applications, also called client applications or clients, and service providers, or driver-like components that translate the features of a specific messaging system into features that any MAPI client application can access. Applications with such diverse messaging needs as a word processing application requiring only the ability to send documents and a workgroup application requiring the ability to share and store different types of data can use the MAPI programming interface to fulfill their needs. In fact, any application that has to either exchange or store information in a particular format can benefit from using the MAPI programming interface. Any service provider can use the interface to expose the unique features of its messaging system, selecting those features that provide the most benefit to application users.

MAPI provides separation between the programming interface used by the front-end messaging client applications and the programming interface used by the back-end service providers. Separating the client interface from the service provider interface enables a single application to use multiple messaging systems and a single service provider to be used by multiple applications. Every component works with a common, Microsoft Windows-based user interface. This is a great benefit to users. Users can select from a variety of systems, depending on their needs at any one time, and be able to work consistently with each selected system, thereby providing true independence from specific messaging systems.

For example, one messaging client application can be used to receive messages from a fax, a bulletin board system, a host-based messaging system, and a LAN-based system. Messages from all of these systems can be placed in a single location upon arrival, or universal Inbox. Having a single application handle all of these systems lessens the cost of development, user training, and system administration.

Separating the client interface from the provider interface removes any programming dependencies placed on the application by the messaging system and vice versa. Developers of client applications and service providers code to a standard set of MAPI features, rather than a diverse set of application-specific or messaging system-specific features. Developers focus only on their component, whether it be a client or service provider, and MAPI handles the rest, thereby reducing development time and costs.

The MAPI programming interface provides a comprehensive set of features. MAPI is aimed at the powerful, new market of workgroup applications — applications that communicate with such different messaging systems as fax, DEC All-In-1, voice mail, and public communications services such as AT&T Easylink Services, CompuServe, and MCI MAIL. The MAPI interface allows service providers to be made available for all of these systems.

Because workgroup applications demand more of their messaging systems, MAPI offers much more than basic messaging in the programming interface and supports more than local area network (LAN)–based messaging systems. Applications can, for example, format text for a single message with a variety of fonts and present to their users a customized view of messages that have been filtered, sorted, or preprocessed.

MAPI is built into the Microsoft Windows family of operating systems; it is a component of the Microsoft® Windows® 95 operating system and Microsoft® Windows NT® operating system. Because MAPI is an integrated part of the operating system, developers of 16-bit and 32-bit Windows-based applications can have access to a consistent interface. This approach is similar to the approach used by the Windows printing system. Just as a word-processing program can print to many different printers through the Windows printing system as long as the necessary drivers are installed, so can any MAPI-compliant application communicate with any messaging system as long as the appropriate service providers are installed.

The programming interface and subsystem contained in the DLL are based on the object oriented concepts introduced with another integrated part of the Windows operating systems, OLE. MAPI-compliant objects conform to the OLE methodology known as the Component Object Model (COM). COM objects implement a set of methods that belong to one or more interfaces, or collections of related functions that define how objects behave and operate within the COM world. Users of COM objects access them only through pointers to these interfaces.

In addition to the DLL and programming interface, several other components are included with the operating system as part of MAPI. There are standard messaging client applications that demonstrate different levels of messaging support. There are sample address book, message store, and transport providers written in both C and C++. You can use these components either for testing your own client or service provider or as a learning tool.

MAPI provides cross platform support through such industry standards as SMTP, X.400, and Common Messaging Calls (CMC). MAPI applications can be run on all 16-bit Windows 3.x platforms and both 16-bit and 32-bit platforms on Windows 95 and Windows NT. MAPI is the messaging component of an open architecture standard known as the Microsoft Windows Open Services Architecture (WOSA). WOSA standards exist or are being developed in the areas of database, directory, security, and messaging technology among others. WOSA programming interfaces allow developers to create front- and back-end components with the confidence that these products can be easily connected in a distributed computing environment.


About the MAPI Architecture

MAPI defines a modular architecture, as shown in the following illustration.

There are basically three types of client applications: messaging-aware, messaging-enabled, and messaging-based. These applications are known as client applications because they are clients of the MAPI subsystem. Messaging-aware and messaging-enabled applications are typically applications not primarily focused on messaging; these are word processing or spreadsheet applications — for example — that incorporate messaging as an added feature. Messaging-based applications employ messaging as a central part of their processing and offer extensive messaging features, such as the exchange of information of various types in various formats and the ability to save and organize the information locally. Electronic mail, scheduling, and work flow applications are examples of messaging-based applications.

The MAPI subsystem is made up of the MAPI spooler, a common user interface, and the programming interfaces. The MAPI spooler is a separate process responsible for sending messages to and receiving messages from a messaging system. The common user interface is a set of dialog boxes that gives client applications a consistent look and users a consistent way to work.

MAPI has programming interfaces that are used by the MAPI subsystem, by client application writers, and by service provider writers. The main programming interface is an object-based interface known as the MAPI programming interface. Based on the OLE Component Object Model, the MAPI programming interface is used by the MAPI subsystem and by messaging-based client applications and service providers written in C or C++.

Client application writers have a choice of three other interfaces:

  • Simple MAPI. An API function-based client interface for applications written in C, Microsoft Visual C++, or Microsoft Visual Basic.
  • Common Messaging Calls (CMC). An API function-based client interface for applications written in C or C++.
  • Active Messaging Library. An object-based client interface for applications written in C, C++, Visual Basic, or Visual Basic for Applications.

The Simple MAPI, CMC, and Active Messaging Library client interfaces are primarily for messaging-aware and messaging-enabled client applications. These interfaces are less complex; applications that require fewer messaging features can use Simple MAPI, CMC, or the Active Messaging Library to implement these features quickly and easily.

Client application writers have the option of making MAPI calls either directly through the MAPI programming interface or indirectly through one of these three client-only interfaces. Messaging can be implemented with a single MAPI client interface or a combination of interfaces. A single application can make calls to methods or functions belonging to any of the interfaces.

The service provider programming interface is the part of the object-based MAPI programming interface that applies specifically to service providers. Service providers, positioned between the MAPI subsystem and the underlying messaging systems, translate requests from MAPI-compliant client applications into tasks a specific messaging system can understand. When tasks are complete, the service providers translate again, converting status and information that is messaging system-specific into a MAPI format. As with client applications, there are different types of service providers. Each type handles a different messaging system service. The address book provider, for example, works with directory information while the transport provider handles message transmission and reception.


About Client Applications

A MAPI client application is any application that uses one of the three MAPI client interfaces (Simple MAPI, CMC, and the Active Messaging Library) or the MAPI programming interface. Client applications implement messaging tasks as either their primary or secondary focus. Messaging client applications, such as applications that send and receive electronic mail, implement messaging as their primary focus while for non-messaging client applications, such as inventory or configuration applications, it is a secondary feature.

Client applications can be organized into one of the following three categories:

  • Messaging-aware applications
  • Messaging-enabled applications
  • Messaging-based workgroup applications

A messaging-aware application does not require the services of a messaging system, but includes messaging options as an additional feature. For example, a word processing application that includes a Send command in its File menu to allow documents to be sent is considered messaging-aware.

A messaging-enabled application requires the services of a messaging system and typically runs on a network or an online service. An example of a messaging-enabled application is Microsoft Mail.

A more advanced client application is the messaging-based workgroup application. The workgroup application requires full access to a wide range of messaging system services, including storage, addressing, and transport services. These applications are designed to operate over a network without users having to manage the applications' network interaction. Examples of such applications include work flow automation programs and bulletin board services.

Client applications can either include the user to create an interactive environment or operate without a user in an automated environment. While MAPI supplies a set of common dialog boxes with its standard user interface, client applications are not required to present a user interface. In fact, all processing can be handled within the application if desired. An example of an automated client application would be an inventory management application that is programmed to route items of a particular type to standard recipients on a regular basis.


About the MAPI Subsystem

The MAPI subsystem consists of the following parts:

  • Client and service provider programming interfaces
  • MAPI spooler
  • Common user interface

The MAPI programming interface is based on a powerful, object-oriented interface that subscribes to the OLE Component Object Model, a model for object interaction. MAPI defines a set of objects that share structure and behavior, enabling developers to create and use objects in a consistent manner. There is a large feature set available, enabling client developers, for example, to provide their users with access to message or recipient properties and customized views of message and address book information. Although all types of client applications can use the object-oriented MAPI interface, typically only messaging-based applications and service providers need its power and complexity. A simpler, more restrictive API is usually sufficient for messaging-aware and messaging-enabled applications.

To support a wider audience of client application developers, there are three other API sets on top of MAPI: Common Messaging Calls (CMC), Simple MAPI, and the Active Messaging Library. Simpler to use and understand, these API sets provide messaging functionality through either C standard function calls or Visual Basic. Client application developers can choose the API that is most suitable for their needs.

The following table describes each of the interfaces available to client applications.

Client interface | Description
Simple MAPI | Supports existing messaging-enabled and messaging-aware applications. For C, C++, or Visual Basic client applications.
CMC | Supports cross-platform applications written in C or C++.
Active Messaging Library | Supports Automation controllers written in C, C++, Visual Basic, or Visual Basic for Applications.
MAPI | Supports full-featured client applications and service providers written in C or C++.

The following illustration shows how Simple MAPI, CMC, and the Active Messaging Library are layered between MAPI and client applications. Messaging-based clients call directly into MAPI while messaging-aware and messaging-enabled clients call into Simple MAPI, the Active Messaging Library or CMC. Calls to these higher level APIs are forwarded to MAPI.


About the MAPI Spooler

The MAPI spooler is a separate process within the MAPI subsystem, responsible for sending messages to and receiving messages from a messaging system. The MAPI spooler plays a vital role in message receipt and delivery. When a messaging system is unavailable, the MAPI spooler stores the messages and automatically forwards them at a later time. This ability to hold on to or send data when necessary is known as store and forward, a critical feature in environments where remote connections are common and network traffic is high. The MAPI spooler runs as a background process, doing much of its work when a client application is idle, thus improving the responsiveness of the client application.

The MAPI spooler has additional responsibilities related to message distribution. These extra duties include:

  • Keeping track of the recipient types that are handled by specific transport providers.
  • Informing a client application when a new message has been delivered.
  • Invoking message preprocessing and postprocessing.
  • Generating reports that indicate that message delivery has occurred.
  • Maintaining status on processed recipients.

The following illustration shows at a high level how a message flows from a client to the messaging system. The user of a client application sends a message to one or more recipients. The message store provider initiates the sending process, formatting the message with additional information needed for transmission.

The MAPI spooler receives the message if:

  • The message store provider is not tightly coupled with the transport provider that can handle all of the recipients to whom the message is addressed.
  • The message requires preprocessing.
  • The message store and transport provider are tightly coupled, but they cannot handle all the recipients to whom the message is addressed.

If the MAPI spooler receives the message, it performs any required preprocessing, and delivers it to the appropriate transport provider. The transport provider gives the message to its messaging system which sends it to its intended recipient.

With incoming messages, the flow is reversed. The transport provider receives a message from its messaging system and notifies the MAPI spooler. The spooler performs any necessary postprocessing and informs the message store provider that a new message has arrived. This notification causes the client to refresh its message display, enabling the user to read the new message.


About Service Providers

Between the MAPI subsystem and the messaging systems are the various service providers. Service providers are drivers that connect MAPI client applications to an underlying messaging system. There are several types of service providers, but not all types are common. Most messaging systems include three types of services: message store providers, address book or directory providers, and message transport providers. Other less typical service providers include messaging hook providers and profile providers. MAPI supports each type of service independently, allowing a vendor to offer one or more custom service providers. For example, a vendor might want to create an address book provider that uses a corporate telephone book directory of employees or create a message store provider that uses an existing database.

Service providers are typically written by software developers with specialized knowledge or experience with a messaging system. In many cases, this is the company or organization which promotes a specific messaging system. For instance, CompuServe supplies address, message store, and transport providers for the CompuServe Information Service. MAPI supplies two of its own service providers: a message store provider known as Personal Folders and an address book provider known as the personal address book (PAB). These providers can be used in isolation, as a client's only message store or address book provider, or in combination with other service providers.

MAPI presents client applications with a unified view of address book and transport provider information. This integrated approach saves the client application from having to map data to the appropriate provider and the user from having to negotiate among addressing schemes used by multiple address book and transport providers. Message store provider information, however, is not unified and clients that use multiple message store providers are responsible for handling them individually.

The service providers work with MAPI to create and send messages in the following way. Messages are created using a form that is appropriate for the specific type, or class, of message. Many messages are made with the standard note form that comes with the MAPI subsystem, either by the user of a client application or programmatically without user interaction. The completed message is addressed to one or more recipients — a user or group of users designated to receive the message. A recipient might or might not have an entry in a directory owned by one of the installed address book providers. Recipients that are not associated with an installed address book provider are called custom recipients or one-off addresses. A one-off address can be temporary, lasting only until the message is submitted, or more permanent if it is saved in the personal address book (PAB) or another modifiable address book.

When the client application sends the message, the message store provider checks that each recipient has a unique and valid address and that the message has all of the information necessary for transmission. If there is a question about a recipient, such as can occur when there are multiple recipients with the same name, an address book provider takes care of resolving the ambiguity. The message is then placed in the outbound queue.

If the message store is tightly coupled to a transport provider that can handle all of the recipients and there is no required preprocessing, the message goes directly to the transport provider without intervention from the MAPI spooler. Otherwise the MAPI spooler performs preprocessing if necessary and attempts to route the message to a transport provider based on the address type of the recipient. If the appropriate transport provider is available, the MAPI spooler transfers the message and the transport provider delivers it. If the transport provider is not available, the MAPI spooler either holds on to the message until the transport provider becomes available or sends it using another appropriate transport provider.


About Address Book Providers

Address book providers handle access to directory information. Directory information consists of data for two types of message recipients: individual messaging users and groups of messaging users who are commonly addressed together called distribution lists. Depending on the type of recipient and the address book provider, there is a wide range of information that can be made available. For example, all address book providers store a recipient's name, address, and address type.

Each address book provider organizes this data using one or more containers. The number and structure of the containers is dependent on the address book provider's implementation. For example, one address book provider might use a single container to hold all of the information, another might use one top-level container that holds subcontainers, a third might use several top-level containers, each holding subcontainers. An address book container hierarchy can be quite deep; there is no limit to the number of subcontainers that can be used.

The following illustration shows the typical MAPI address book organization.

MAPI integrates all the information supplied by the installed address book providers into a single address book, presenting a unified view to the client application. The integrated list shows the top-level containers displayed by each of the installed address book providers. Most address book providers expose only a few containers (typically one to three) at the top level for inclusion in the top level of the MAPI integrated address book. For example, an address book provider might make available All Users and Local Users as two containers at the top level.

The users of client applications can view the contents of address book containers and in some cases modify it. Address book containers can be created with different access levels, depending on the address book provider. The MAPI personal address book (PAB) is an example of a modifiable address book container that allows new entries to be added and existing entries to be modified or deleted. The PAB is a special container because it allows users to store copies of frequently used addresses and maintains custom recipient entries, or new entries that do not exist in the information maintained by one of the installed address book providers. Custom recipients may be created for the duration of the session only or be stored in the PAB for greater longevity.

Whereas the PAB is an address book provider supplied by MAPI, it is also a role that any modifiable address book container can play. A user can take another modifiable address book container and assign it as the PAB, replacing the MAPI personal address book as the default PAB.


About Message Store Providers

Message store providers handle the storage and retrieval of messages and other information for the users of client applications. The message information is organized using a hierarchical system known as a message store. The message store is implemented in multiple levels, with containers called folders holding messages of different types. There is no limit to the number of levels in a message store; folders can contain many subfolders.

The hierarchical message store architecture is shown in the following illustration. There are two folders, one with a subfolder. Client application users can access a summary view of the messages contained within each folder or view them individually with a form. Whether the client displays a standard form supplied by MAPI or a custom form supplied by a form developer depends on the type, or class, of the message. The first folder contains note messages and uses the MAPI standard note form. The second folder contains inventory request messages and uses a custom inventory form. The information on both forms represents the properties of the message.

Message store data can be used in a variety of ways. Besides the traditional electronic mail usage, folders can be used as a forum for public discussion, as a repository for reference documents, or as a container for bulletin board information, to name a few. A single message store can hold many types of information, some modifiable and some not. Multiple clients can install the same message store, making the sharing of data easy and fast.

Message store folders provide the means for sorting and filtering messages and for customizing their view in a user interface display. Links to filtered messages are held in special folders called search-results folders. The user of a client application enters filtering criteria, which MAPI refers to as a restriction, and the criteria is applied to the messages stored in one or more folders. For example, a user might want to view only those messages dealing with a particular subject with arrival dates that are more recent than last week. References to the messages that match the criteria are listed in the search-results folder and the real messages remain in their regular folders.

Messages are the units of data transferred from one user or application to another user or application. Every message contains some message text, formatted simply or more intricately, and message envelope information that is used for transmission. Some messages include one or more attachments, or additional data related to and transported with a message in the form of a file, another message, or an OLE object.

Depending on the message store provider, a user can save a new message currently under composition as well as messages that have been sent or received. Messages can be copied or moved from one folder to another with each copy becoming a separate message that can be copied, deleted, or modified individually. Another feature that some message store providers allow is the ability to change a message, once it has been received, and store it back in its folder. A user might take advantage of this feature for rotating a fax message that has arrived upside down. The correct view can be stored in the folder for later viewing.


About Transport Providers

Transport providers handle message transmission and reception; they control the interaction between the MAPI spooler and the underlying messaging system and implement security if necessary. They also take care of any preprocessing and postprocessing tasks that are necessary. There is typically one transport provider for every active messaging system.

Client applications communicate with the transport provider through a message store provider. The message store and transport provider communicate through the MAPI spooler. When an incoming message is detected, the transport provider informs the MAPI spooler and the message is delivered to the appropriate message store. To handle outgoing messages, the processing happens in reverse: the message store provider moves the message to the outbound queue, informs the MAPI spooler, and the MAPI spooler transfers it to the appropriate transport provider. When possible, calls to the transport provider are made when client applications are idle. Transport providers and the MAPI spooler operate in the background except at logon time and when prompted by the client application to flush the transmit and receive queues.

Transport providers register with MAPI to handle one or more particular types of recipient entries. When a message is ready to be sent, the MAPI spooler looks at each recipient and determines which transport provider should handle the transmission. Depending on the type of recipient, the MAPI spooler can even call upon more than one transport provider. If the MAPI spooler's first choice is unavailable, and another transport provider has also registered to handle the specific recipient type, the MAPI spooler sends the message to the alternate provider. If the unavailable transport provider is the only one that can handle the recipient, there is no choice except to wait until a connection with that provider can be reestablished.

Some messaging systems are secure systems; all potential users are required to enter a set of valid credentials before access is permitted. MAPI prevents unauthorized access to such secure messaging systems by having the transport provider validate credentials at logon time.


About Message Services

A message service defines a group of related service providers, typically service providers that work with the same messaging system. Whereas service providers perform the work of interfacing between messaging systems and the MAPI subsystem, message services perform the work of interfacing between service providers that work with a common messaging system and the user.

Message services exist to make the installation and configuration of service providers easier for users. Users never directly install or configure a service provider; this installation and configuration is completely handled by the message service, making knowledge of service provider configuration requirements unnecessary. For example, when a user wants to install the service providers for the CompuServe Information Service, that user installs a single message service. The installation component in the message service handles the installation of each of the service providers that belong to the service.

The following illustration shows the relationship between a messaging-based client application and two message services. The user invokes the installation code of each message service to add the service and its service providers to a profile. In one of the message services, there are three service providers and in the other there are two. At some later time after installation is complete, typically at logon time, the service providers in each message service are configured. The configuration code in each message service handles the configuration of the providers in the service.

When a message service is installed, its installation program copies necessary files from the installation source to the user's local disk and updates a configuration file, MAPISVC.INF. The MAPISVC.INF file holds configuration settings for all of the message services and service providers that can be installed on the computer. It is organized in hierarchical sections, with links between each section at each level. The section at the top level contains information relevant for the MAPI subsystem, such as a list of all available message services, and for the online help installation. The next level has sections for each message service, with information such as the DLL filename of the message service and the name of its configuration entry point function. The third level has sections with configuration data for each service provider in the message services.

To handle configuration, a message service implements an entry point function that conforms to a prototype defined by MAPI and a tabbed dialog box known as a property sheet. MAPI calls the entry point function to service client requests that relate to profile management and the management of service providers within the message service. Property sheets are used for viewing and changing message service and service provider configuration properties.


About Profiles

A profile is a collection of information about the message services and service providers that a user of a client application wants to be available during a particular MAPI session. Every user has at least one profile; many users keep several. For example, a user might have one profile to work with a server-based message store service and another profile to work with a message store service on the local computer. A user might want to access one set of messaging systems using the appropriate transport services for part of the day and another set for the rest of the day. Profiles provide a flexible way to select combinations of messaging system services.

Profiles can be given names up to 64 alphanumeric characters in length. The names can include accent characters, the underscore, and embedded spaces and cannot include leading or trailing spaces. Profiles can have passwords, but are not required to have them because not all operating systems support them. Currently, Windows NT and Windows 95 do not support passwords, but Windows version 3.1 does.

Profiles are organized hierarchically and divided into sections, with one section for each message service and one section for each service provider within a service. The related sections are linked, making it easier to navigate through the information. Each section contains a series of entries that MAPI or a client application uses for configuration.

The entries included in a profile vary from message service to message service. Some of the common entries include:

  • Name of each message service or service provider
  • Name of the DLLs that contain service providers and message services
  • Name of each message service's entry point function
  • A list of the service providers that make up each message service

Profiles can be created at installation time, when MAPI or a message service is loaded onto a computer workstation, or at any time after. MAPI provides three programs for profile administration: the Control Panel applet, the Profile Wizard, and the NEWPROF utility.

The Control Panel applet is a full-featured configuration application, allowing a user to create new profiles and maintain existing profiles either by deleting them or adding, modifying, or deleting entries.

The Profile Wizard is an application that creates new profiles with a minimum amount of work. Default values for settings are used wherever possible, saving users time and effort. Users enter values only when absolutely necessary.

The NEWPROF utility is a tool for creating new profiles with a template file similar to MAPISVC.INF called DEFAULT.PRF. The entries that are placed in DEFAULT.PRF are written into the new profile as properties. NEWPROF can be invoked from the command line, a message service installation program, or from within a client application.


About MAPI Forms

A MAPI form is a viewer for a message. Every message has a message class that dictates the particular form that is used as its viewer. MAPI defines a few message classes and has implemented the forms for viewing messages of these classes. Client application developers can create new message classes and custom forms for viewing messages created with the new classes.

Every custom form implements a set of standard menu commands, such as Open, Create, Delete, and Reply and a set of commands that are specific to the particular form. Some of the form commands are integrated with the user interface of the client application when the form is active; other form commands totally replace the client commands.

The relationship between the MAPI components involved in using forms is shown in this diagram. Following is a brief description of the components involved; more detailed descriptions are provided in Forms.

In the diagram, notice that the form manager plays a role that is similar to other MAPI service providers, although it is not a service provider itself. That is, the form manager is a replaceable DLL that implements a portion of the MAPI interfaces. Although developers can implement their own form manager, most environments will use the form manager provided by Microsoft due to the form manager's complexity.

The components shown in the diagram and their relationship to other components are:

  • Messaging client: An application that is able to use form objects. The messaging client uses the MAPI form interfaces to communicate with the form manager in order to load messages into form objects.
  • MAPI form interfaces: A defined standard for communication between MAPI components that are related to forms.
  • Form manager: The DLL that messaging clients use to handle installation of forms in form libraries, loading of form servers, and initial communication between messaging clients and form servers.
  • Form libraries: Permanent storage for the executable files associated with form servers.
  • Form servers: Executable files which implement a form. Form servers create form objects and user interfaces to deal with specific messages. This executable is also an OLE server and adheres to the usual OLE conventions.
  • Form objects: Run-time objects created by form servers that correspond to specific messages. Form objects run in the same process context as their form server.


Introduction to MAPI Programming

The MAPI Programmer's Reference is written for C and C++ developers with a wide range of needs and experience with messaging. For those developers who want to use MAPI to augment their nonmessaging applications with messaging features, no specific prerequisite knowledge is required. However, for developers intending to use MAPI to create full-scale workgroup applications or drivers for specialized messaging system services, a background in messaging and a familiarity with the Component Object Model (COM) used with OLE is recommended.

Before beginning serious development work, you need to consider the following information about using the MAPI Software Development Kit (SDK), the logon process, and how profiles and message services are created and configured. Client application developers need to consider how to choose between the four client APIs (MAPI, Simple MAPI, CMC, and the Active Messaging Library) and how to create a client application that takes advantage of more than one client API.


Installing MAPI

Information about a computer's MAPI installation can be found in the system registry on 32-bit client applications and in the Windows initialization file, WIN.INI, for 16-bit client applications. The system registry and WIN.INI file contain the same information about the MAPI libraries that are installed on the computer and options about use. All values in the registry entries are character strings.

Message service installation programs are responsible for creating the installation information in the [Mail] section of the WIN.INI file and in the following system registry key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Messaging Subsystem

Message services can add entries to either the WIN.INI file, the system registry, or both resources depending on the installation.

The following table summarizes how clients retrieve version information and determine if Simple MAPI, CMC, MAPI, or the Active Messaging Library is available on their machine.

To check | Registry/WIN.INI entry
Availability of Simple MAPI | Look for MAPI=1
Availability of MAPI | Look for MAPIX=1
Availability of CMC | Look for CMC=1
Availability of Active Messaging Library | Look for OLEMessaging=1
Available version of MAPI | Look for MAPIXVER string of the form: x.x.x

Note Client applications that are running Windows NT 3.51 or earlier must check the WIN.INI file rather than the registry for the MAPIX=1 entry to determine the availability of Simple MAPI.


Determining Which Client Interfaces are Installed

The information that is added to the [Mail] section of the WIN.INI file or the system registry specifies the types of MAPI client application programming interfaces (APIs) that are installed on a computer. These types include Simple MAPI, MAPI, the Active Messaging Library, and CMC. If CMC is installed, another entry exists to identify the name of the CMC DLL that should be loaded for your system.

The entries that identify client API installations are as follows:

[Mail]
MAPI=0 or 1
MAPIX=0 or 1
OLEMessaging=0 or 1
CMC=0 or 1

Each entry that represents an installed MAPI client API is set to 1. If a particular client API is not installed, its entry either is missing from the WIN.INI file or the registry or is set to 0. The MAPI entry identifies a Simple MAPI installation, the MAPIX entry identifies the more complete MAPI installation with all of the object oriented interfaces and its related functions and macros, and the Active Messaging Library and CMC entries indicate the client API of the same name.

Computers with CMC installations can also set the CMCDLLNAME or CMCDLLNAME32 entries to specify the filename of the CMC DLL. CMCDLLNAME identifies the 16-bit version; CMCDLLNAME32 identifies the 32-bit version. If these entries are omitted and a CMC installation exists, MAPI searches for a file named CMC.DLL regardless of whether the installation is for a 16-bit or 32-bit platform. The format of the CMCDLLNAME entries is as follows:

CMCDLLNAME=full path to file
CMCDLLNAME32=full path to file

All of the types of MAPI installations reside in a standard DLL. Simple MAPI, CMC, and MAPI reside in MAPI.DLL for 16-bit platforms and MAPI32.DLL for 32-bit platforms. The Active Messaging Library resides in OLEMSG.DLL for 16-bit platforms and OLEMSG32.DLL for 32-bit platforms. Active Rendering resides in AMHTML.DLL.

Both 16-bit and 32-bit Simple MAPI client applications can run in an environment that supports both platforms (for example, the Windows 95 and Windows NT operating systems) if there is a Simple MAPI installation available for at least one of the platforms. Client applications do not need the name of the server executable file; information contained in the OLE registry automatically binds the appropriate file.

Microsoft supplies an import library for MAPI. Client applications can load the MAPI DLL statically using the import library or load it dynamically using the Windows API functions LoadLibrary and GetProcAddress.

There is no import library for either the Simple MAPI DLLs or the CMC DLLs. These DLLs must always be loaded dynamically by calling the Windows functions LoadLibrary and GetProcAddress. Applications that use these functions to load a CMC, Simple MAPI, or MAPI DLL should always check either the appropriate CMC, MAPI, or MAPIX entry to determine if the API is installed before attempting to load the DLL.

The specific version of MAPI is indicated by another string value, which is a four-part number as follows:

MAPIXVER=w.x.y.z


MAPI Installation Defaults

MAPI supplies a default profile provider implementation and a set of common dialog boxes. Typically, service providers will use what MAPI provides. However, it is possible to replace either the profile provider implementation or the set of common dialog boxes. A provider can specify versions of these components in the [MAPI] section of the WIN.INI file or the system registry. Service providers that use the default components need not include this section.

The following entries can be included in the [MAPI] section:

Profile DLL=full path to file
Dialogs=full path to file
ProfileDirectory16=full path to file

The Profile DLL entry specifies the name of the DLL for the MAPI profile provider. The default setting is MAPI.DLL for 16-bit platforms and MAPI32.DLL for 32-bit platforms. The filename included in the path should be the profile provider's base DLL name, that is the DLL name without the suffix.

The Dialogs entry specifies the name of the DLL that contains the implementation for the common dialog boxes. The default setting is WMSUI.DLL for 16-bit platforms and WMSUI32.DLL for 32-bit platforms.

The ProfileDirectory16 entry specifies the path to the directory where the profile files are kept. This entry is supported for 16-bit Windows environments only. The default location is a subdirectory named MAPI under the Windows directory. The ProfileDirectory16 entry can be set either by the user or automatically — for example, by a network logon script. Specifying an explicit path for profile files allows you as a service provider to store these files on a server computer rather than locally, allowing them to be accessed from anywhere in the network.


Time Zone Information

The [MAPI 1.0 Time Zone] section stores information that is used by the MAPI 16-bit implementation of the time-zone API functions provided by 32-bit Windows. The entries that appear in this section are as follows:

[MAPI 1.0 Time Zone]
Bias=minutes
StandardName=string
StandardStart=time structure
StandardBias=minutes
DaylightName=string
DaylightStart=time structure
DaylightBias=minutes

The TIME_ZONE_INFORMATION structure is defined as follows in the Microsoft Platform SDK documentation.

typedef struct _TIME_ZONE_INFORMATION
{
    LONG       Bias;
    WCHAR      StandardName[ 32 ];
    SYSTEMTIME StandardDate;
    LONG       StandardBias;
    WCHAR      DaylightName[ 32 ];
    SYSTEMTIME DaylightDate;
    LONG       DaylightBias;
} TIME_ZONE_INFORMATION;


Using the MAPI SDK

The MAPI Software Development Kit (SDK) includes tools to help in the development of MAPI-compliant client applications, service providers, and message services. The MAPI SDK is distributed with the Microsoft Developer's Network (MSDN) Professional subscription. There are two versions of the MAPI SDK: one for 16-bit developers and one for 32-bit developers.

You can install and use the MAPI SDK on any computer that meets the minimum qualifications for Microsoft Windows version 3.1 (enhanced mode only), Microsoft Windows NT version 3.51 or later, or Microsoft Windows 95.

The MAPI SDK contains the following components:

  • MAPI runtime setup program
  • MAPI header files and libraries
  • MAPI runtime files
  • Sample client applications and service provider source code
  • Microsoft Exchange client
  • SDK tools
  • Help files

For configuration, MAPI provides two applications: a Control Panel applet for full configuration support and the Profile Wizard for basic profile administration.

The 32-bit version of the MAPI SDK is installed with the Platform SDK.


Using UUIDGEN.EXE

UUIDGEN.EXE is a Microsoft utility that generates unique, byte-order independent identifiers. This utility has several uses in the MAPI environment. The following table indicates some of the ways that MAPI components can use this utility.

MAPI component | Use of UUIDGEN.EXE
Service provider | Creating new hardcoded MAPIUIDs.
Form | Creating new class identifiers for forms.
Client application or service provider | Identifying hardcoded global profile section.
Client application or service provider | Creating new property sets for named properties.


Testing and Debugging

Testing strategies differ depending on whether you are developing a client or service provider. Because a client application requires one or more service providers to operate, clients should be tested in an environment with different sets of service providers.

Service providers, however, should be tested in isolation before being integrated with other providers. MAPI provides tools that are meant to test the features of a service provider of a particular type. ABVIEW.EXE (for 16-bit platforms) and ABVIEW32.EXE (for 32-bit platforms) exercises the features of an address book provider. MDBVU.EXE (for 16-bit platforms) and MDBVU32.EXE (for 32-bit platforms) works with a message store provider.

To test any service provider in isolation, use one of these sample applications and limit the entries in the profile the provider to be tested. Include any other service providers that are absolutely necessary. For example, to test a transport provider, your profile would contain that provider, the personal address book (PAB), and a message store. For more information about these tools, see Address Book Viewer and Message Store Viewer.

All clients and service providers can benefit from using a set of debugging macros provided by MAPI in the MAPIDBG utility. This utility is controlled by the entries in its initialization file, MAPIDBG.INI. MAPIDBG.INI is used to control various features of the MAPI subsystem. The file resides in the Windows directory and is organized in sections, similar to other Windows initialization files and MAPISVC.INF. Sections are labeled in the following format with each section containing several entries that affect the utility's behavior:

[SectionName] Section

For detailed information about the various sections in the MAPIDBG.INI file, see File Format of MAPIDBG.INI.


Selecting a Client Interface

Client application developers can choose to use one or more of the MAPI client interfaces: Simple MAPI, CMC, MAPI, and the Active Messaging Library. Consider the following factors before making a decision:

  • Programming language
  • Time constraints
  • Resource constraints
  • Type of client application

The language in which your client application will be written or is written is an important issue. If you are modifying an existing application, you must use a client interface that supports your application's language. If you are writing a new client application, the choice of language depends on your experience with the supported languages and any requirements for interoperability that might exist with other components. All of the client interfaces work with C and C++, whereas Visual Basic developers are limited to using the Active Messaging Library and Simple MAPI.

The amount of time you need to create or modify your client application is also a consideration. A simple API such as Simple MAPI or CMC is more appropriate if you have limited time. Resource constraints might also be an issue. To successfully develop a client application, you should have experience with messaging and the appropriate programming language.

Messaging-enabled and messaging-aware client applications have different requirements than messaging-based applications. Messaging-enabled and messaging-aware applications have fewer and simpler messaging features to implement. Messaging-based applications have more complex messaging requirements because they have more direct contact with and control over the underlying messaging system services like address books, message stores, and transports. These applications often implement a wide variety of messaging features, such as rules processing, automatic forwarding, and supporting Rich Text Format. Shared group applications like schedulers and calendars, work flow and message management applications, electronic mail clients, and rules-based Inbox managers are examples of messaging-based applications. Complex messaging-based applications like these require the MAPI client interface.

The Active Messaging Library is a good choice for applications that require a moderate amount of messaging support. The Active Messaging Library is an object oriented API used primarily by Visual Basic and Visual C/C++ client application developers. It provides programmable objects that publish properties and methods which can then be managed by Visual Basic and Visual Basic for Applications programs or other Automation controllers. The Active Messaging Library is based on the capabilities provided by Automation. In terms of messaging functionality, it offers more than CMC and Simple MAPI offer, but less than MAPI offers.

Simple MAPI or CMC is the best choice for messaging-enabled and messaging-aware applications. These interfaces provide a fast and easy way to build basic applications from scratch or add messaging functionality to existing applications.


Client Interfaces

The following table summarizes the differences between the characteristics of the four client interfaces.

Issues | CMC | Simple MAPI | MAPI | Active Messaging Library
Messaging support | Low | Low | High | Medium
Prerequisite knowledge | None | None | COM and OLE | Automation and Visual Basic programmable objects
Forms support | None | None | Full support | Some support
Language support | C and C++ | C, C++, Visual Basic | C and C++ | C, C++, Visual Basic
Platform support | Cross- platform | Windows- based | Windows- based | Windows- based


Choosing Between Simple MAPI and CMC

The features provided by Simple MAPI and CMC are nearly identical, but CMC is slightly more compact, combining multiple features in a single function. Both interfaces provide a straightforward function call interface that enables users to create, send, receive, reply to, forward, and edit messages.

The following table lists all the functions in the CMC and Simple MAPI APIs together with the features they provide.

Purpose | Simple MAPI function | CMC function
Establish a session | MAPILogon | cmc_logon
Terminate a session | MAPILogoff | cmc_logoff
Free memory | MAPIFreeBuffer | cmc_free
Send a message with or without a user interface | MAPISendMail | cmc_send
Send a message with a user interface | MAPISendDocuments | cmc_send_documents
Find messages that match a set of search criteria | MAPIFindNext | cmc_list
Save a message | MAPISaveMail | cmc_act_on
Delete a message | MAPIDeleteMail | cmc_act_on
Assign recipients to a message | MAPIAddress | cmc_look_up
Show recipient details | MAPIDetails | cmc_look_up
Resolve ambiguous names in recipient list | MAPIResolveName | cmc_look_up
Retrieve configuration data | - | cmc_query_configuration

The main difference between the two APIs is that CMC is designed to be independent of the operating system. CMC was developed in conjunction with the X.400 Application Programming Interface Association (XAPIA) standards organization and electronic mail vendors and users. Because CMC runs on Windows, MS-DOS, and UNIX systems, it is a good choice for client applications that need to use multiple messaging systems on multiple platforms. Because Simple MAPI runs on Windows-based platforms only, it is a good choice for single platform Windows-based client applications that require a feature CMC lacks or that need to be compatible with an existing Simple MAPI application.


Using Multiple Client Interfaces

Most client applications will use one client API — either the Active Messaging Library, Simple MAPI, CMC or MAPI. However, some clients will need to take advantage of what more than one client API has to offer. These clients should use MAPI for some tasks and a simpler API for others. The MAPI architecture allows client applications to do this fairly easily by providing several API functions for converting between the environments.

One common conversion task involves identifiers. Identifiers are used throughout MAPI to uniquely represent a component, such as a message or a service provider. MAPI uses a binary structure called an entry identifier; the Active Messaging Library uses a hexadecimal entry identifier, Simple MAPI uses a string called a message identifier, and CMC uses a string called a message reference. Identifiers can be simple or compound. Compound identifiers are supported by some message stores and are used with messages. They have two parts: one part that contains the record key of the message store and another part that contains the entry identifier of the message.

MAPI only provides the means to convert between MAPI entry identifiers and all other identifiers. It does not provide the means for converting between Simple MAPI and CMC, Simple MAPI and the Active Messaging Library, or CMC and the Active Messaging Library.

The following API functions are used to translate identifiers used by the different client API sets:

FBinFromHex

HexFromBin

HrSzFromEntryID

HrEntryIDFromSz

HrComposeEID

HrDecomposeEID

HrComposeMsgID

HrDecomposeMsgID

The FBinFromHex and HexFromBin functions are used to translate the binary entry identifiers used in the MAPI programming interface and the hexadecimal entry identifiers used in the Active Messaging Library.

The HrEntryIDFromSz function creates a MAPI entry identifier from a Simple MAPI string identifier and the HrSzFromEntryID function performs the opposite operation, producing a Simple MAPI string identifier from a MAPI entry identifier.

The HrComposeMsgID function also creates a Simple MAPI identifer. However, HrComposeMsgID creates a compound entry identifier, or identifier that can be used by Simple MAPI clients to open a nondefault message store. Compound entry identifiers for messages are built from the record key of the message store and the message's entry identifier. A message store's record key is a unique binary value that can be used for comparison. Calling HrComposeMsgID enables Simple MAPI clients to create the identifiers necessary for working with multiple message stores.

The HrComposeEID function is similar to HrComposeMsgID because it is also used for creating compound entry identifiers. However, whereas HrComposeMsgID is primarily for Simple MAPI clients, HrComposeEID is for CMC clients. Callers of HrComposeEID pass a session pointer, a message store record key, and the entry identifier of an object. HrComposeEID produces a MAPI entry identifier based on both the record key and entry identifier, if possible, or only the entry identifier if the record key is not available.

HrDecomposeEID separates a compound entry identifier into its parts: a message store record key and an entry identifier that represents a MAPI object. Use HrDecomposeEID with care; it is an expensive call. Both HrComposeEID and HrDecomposeEID can handle binary message identifiers that require string versions.

Because HrComposeEID, HrComposeMsgID, HrDecomposeEID, and HrDecomposeMsgID all require a MAPI session pointer as input, client applications that are not started with the MAPI logon function, MAPILogonEx, must translate the current session handle into a MAPI session before calling any of these functions. HrEntryIDFromSz, a function that does not require a session pointer, can also be used to create a compound entry identifier. However, subsequent uses of this entry identifier can fail. If possible, clients should use the HrComposeMsgID or HrComposeEID function instead.

Converting session types is possible with one of two API functions: ScMAPIXFromCMC or ScMAPIXFromSMAPI. To convert CMC sessions into MAPI sessions, use ScMAPIXFromCMC. To convert Simple MAPI sessions, use ScMAPIXFromSMAPI. Both functions take the current session handle as input and return a pointer to a MAPI session object.

When using multiple client APIs, exercise caution in interpreting return values. Client APIs do not share the same set of return values, nor do they return the same type of values. For example, Simple MAPI and CMC functions return unique sets of unsigned long values whereas MAPI functions and methods return values that are of type HRESULT. In all cases, zero means a successful result.

The unsigned long values and the HRESULT values are based on a numeric code which, in many cases, is the same for all caller types. However, there are a few cases where the values are different. The following table lists the differences between the values returned by Simple MAPI and MAPI.

Simple MAPI return value | MAPI return value
MAPI_E_NOT_SUPPORTED | MAPI_E_NO_SUPPORT MAPI_E_INTERFACE_NOT_SUPPORTED MAPI_E_INVALID_PARAMETER MAPI_E_VERSION
MAPI_E_DISK_FULL | MAPI_E_NOT_ENOUGH_DISK
MAPI_E_NETWORK_FAILURE | MAPI_E_NETWORK_ERROR
MAPI_E_USER_ABORT | MAPI_E_USER_CANCEL
MAPI_E_ACCESS_DENIED | MAPI_E_NO_ACCESS
MAPI_E_AMBIGUOUS_RECIPIENT | MAPI_E_AMBIGUOUS_RECIP


MAPI User Interface

MAPI provides a set of common dialog boxes that offer a consistent way for users to interact with messaging systems. Simple MAPI, CMC, and Active Messaging Library client applications are presented with these dialog boxes automatically. MAPI client applications and service providers can use the MAPI dialog boxes or implement their own. Unless you have very customized needs, you should take advantage of the MAPI user interface. By doing so, you will save time and give users tools that are consistent across applications and messaging systems.

The MAPI user interface includes many different dialog boxes, some for session start-up, some for addressing, some for message composition. The message composition dialog boxes are used to create interpersonal messages; to create messages of other types, you can implement special dialog boxes, or forms, that can be provided by the originator of the message type. For information about implementing and displaying these special forms, see Developing MAPI Form Servers.


MAPI Sessions

Before your client application can call an underlying messaging system, it must establish a session, or connection, with the MAPI subsystem. Sessions are initiated when a user logs on, a process that consists of accessing a valid profile, validating messaging system and message service credentials, and insuring that all of the profile's message services are properly configured. The client interface you use determines the logon call. MAPI clients call the MAPILogonEx function, Simple MAPI clients call the MAPILogon function, CMC clients call the cmc_logon function, and Active Messaging Library clients call the Session object's Logon method.

MAPI supports the validation of credentials, such as passwords, as an optional feature. The use and implementation of passwords depends on the messaging system being used and the operating system. Some operating systems support security that is based on user accounts; others do not. Passwords can either be saved in the profile or entered by the user with every logon.

The following table lists the MAPI operating systems and whether or not each type implements user account security.

MAPI platform | User account security
Windows 95 | Yes
Windows NT | Yes
Windows 3.x | No
Windows for Workgroups 3.x | No

Message service configuration is one of the most important parts of the logon process. The profile is the initial source for configuration information. If information for a particular message service is missing, the logon process attempts to prompt the user to supply it, an attempt which is not always successful for two reasons. Prompting the user requires the display of a dialog box. It is possible for clients to disallow the display of a user interface by passing a flag into the logon call. A second possible reason for failure is the cancellation of the dialog box by the user before the needed information can be added.

When a logon process fails once, the user is informed of the failure and given the opportunity to retry or correct the error condition. Once again, a user interface will be displayed, if possible, and the user will be prompted to enter whatever data is missing. If this second attempt proves unsuccessful, MAPI disables all service providers in the message service for the duration of the session. In effect, the whole message service is disabled, meaning that none of the service providers in the message service can work. This is done because if one provider fails logon, the other providers usually also fail. The logon process can fail due to an invalid path for a necessary resource, an incompatible version of MAPI, an unavailable messaging server, or data corruption.

Clients can specify one of two types of sessions to be established in the logon call: an individual session or a shared session. Individual sessions are private connections; there is a one-to-one relationship between a client application and the session it is using. As a consequence, client applications sharing a session also share a profile. Shared sessions are established once but can be "used" by other client applications who need to use them. The profile and credentials are specified only with the initial logon.

MAPI also supports unified logon, in which a single initial logon to the messaging system results in access to multiple workgroup applications. When working with unified logon, users do not have to enter a name and password for each application they want to use.

Clients can log on multiple times as the same user or as multiple users. MAPI does not prevent this. Some service providers, however, might not be as flexible, returning the error value MAPI_E_SESSION_LIMIT on subsequent logon attempts. Service providers with underlying hardware limitations can be required to enforce a session limit.

The function calls for establishing a session have a collection of flags and parameters that control how the session is created. The client specifies an optional profile name, password, and a window handle that acts as the parent window for any dialog boxes that are displayed. The flags include MAPI_NEW_SESSION to request that a new, individual session be established rather than establishing a connection to a shared session, and two user interface flags, MAPI_LOGON_UI and MAPI_PASSWORD_UI. The user interface flags are set to request either a logon dialog box or a password dialog box.

The following illustration shows how these various parameters and flags establish a MAPI session.

For information about handling sessions from within a client application, see Session Handling.


Message Services and Profiles

Some users require the services of several messaging systems, each with one or more service providers. Because it is cumbersome to have to install and configure each of these service providers individually and because a messaging server usually requires a group of related providers to expose all of its functionality, MAPI includes the concept of a message service. Message services help users install and configure their service providers.

To create a message service, a developer writes a message-service entry point program to handle the configuration of each provider in the service and a setup program to:

  • Install each provider in the service.
  • Create registry and initialization file entries.
  • Create entries in the MAPI configuration file, MAPISVC.INF.

The MAPISVC.INF file contains information relating to the configuration of all message services and service providers installed on the computer workstation. It is organized in hierarchical sections, with each level linked to the next. At the top are three sections: one listing message service help files, one listing the most important, or default, message services, and one listing all of the services on the workstation. The next level contains sections for each message service and the last level contains sections for each service provider in a service. MAPI requires developers of service providers and message services to add certain entries to MAPISVC.INF; other entries can be added at the developer's discretion. Most of the information in MAPISVC.INF ends up in one or more profiles, a collection of configuration information for a user's preferred set of message services. Because a workstation can have multiple users and a single user can have multiple sets of preferences, many profiles can exist on a workstation. Each profile describes a different set of message services. Having multiple profiles enables a user to work, for example, at home with one set of message services and at the office with a different set.

Profiles are created at message service installation or logon time by a client application that provides configuration support. MAPI provides two such client applications: the Control Panel applet and the Profile Wizard. The Control Panel applet is a full service configuration application that allows users to create, delete, edit, and copy profiles as well as make modifications to the entries within a profile. The Profile Wizard is a simple application designed to make adding a message service to a profile as easy as possible. The Profile Wizard consists of a series of dialog boxes, called property pages, that prompt the user through the process of installing and configuring a service. The user is prompted only for values for the most critical settings; all other settings inherit default values. Once the profile has been created, users are not allowed to make changes.

Whereas the Control Panel applet is always invoked through the Control Panel, there are a variety of scenarios that can cause the Profile Wizard to be called. Client applications can call the Profile Wizard to create a default profile at logon time when one has not yet been created. Rather than reimplementing code to add a profile, the Control Panel applet or another client application can rely on the functionality already in the Profile Wizard. A message service, in its entry point function, can call the Profile Wizard when the service needs to be added to the default profile. Message services that use the Profile Wizard must write an extra entry point function and a standard Windows dialog procedure. The Profile Wizard calls the entry point function to retrieve the service's configuration dialog box while the dialog procedure handles the messages that are generated when this dialog box is in use.

Profiles are organized in a similar way to the MAPISVC.INF file. There are linked hierarchical sections with service providers owning sections in the lowest level, message services owning sections in the middle level, and MAPI owning sections in the highest level. Each section is identified with a unique identifier known as a MAPIUID. The MAPI sections contain information internal to MAPI, such as the identifiers of all of the message service profile sections and links to each of the other sections. Each message service section stores links to its provider sections and each provider section stores a link to its service section.

The following illustration shows the contents of two typical profiles. Sam has two profiles on his computer, one for home use and one for office use. The home profile contains three message services. Message Service X is a single provider service for address book management. Message Services Y and Z have three providers — an address book provider, a message store provider, and a transport provider. Sam's Work Profile contains two different message services; each of which has an address book provider, a message store provider, and a transport provider.

Some profiles, depending on the platform, are password-protected. Password protection is only supported on platforms that do not provide user account security. It can be desirable to password protect profiles if it is important to ensure single user access.

Note Although password-protected profiles can only be changed by valid users, anyone with access to the system can delete them. This is because profiles are not considered critical components; they can be easily recreated.

The following illustration shows a profile that includes two message services. The code for installing and configuring the service providers that belong to the message service reside in the same DLL as the code for the providers. This code reads information from the profile at logon time to configure the service providers and prompts the user, if possible and necessary, for missing information. Requests from a client to view or change configuration settings for any of the providers are also handled by this common code.


Operating Environment Issues

The issues of operating system and operating environment are important when choosing a development environment and an environment for MAPI SDK installation. MAPI developers must be aware that these choices affect the operating system that their component will run on and the range of components that they will be able to target.

MAPI currently runs on the 32-bit environments provided with Windows NT and Windows 95, the native 16-bit environment of Windows 3.1 or later, and a 16-bit compatibility mode environment that allows 16-bit client applications to run on 32-bit platforms. Compatibility mode does not work for service providers.

The choice of development environment affects the environment that your component will be able to operate in. For service providers, the environment used for development is the only environment that their component will be able to operate in. That is, service providers developed in 16-bit environments can operate in 16-bit environments and service providers developed in 32-bit environments can operate in 32-bit environments.

Client applications are slightly more flexible. Clients written in 32-bit environments are like 32-bit service providers; they can only operate in 32-bit environments. Clients written in 16-bit environments, however, can operate in any environment.


Environment Issues Affecting Client Applications

MAPI-compliant client applications can run in multiple environments, depending on the environment used for development. A client written in a 16-bit development environment can operate either in a native 16-bit Windows environment or in any 32-bit environment under 16-bit compatibility mode. Compatibility mode allows a 16-bit application to simulate a 32-bit application. A client written in a 32-bit development environment can run on any 32-bit operating system, such as Windows NT or Windows 95.

The environment into which a client installs the MAPI SDK affects the scope of usable service providers. If the MAPI SDK is installed in a generic 32-bit environment or in the 16-bit compatibility mode environment, a client can use two types of service providers:

  • Service providers written for 32-bit operating environments
  • Single-source service providers

Single-source service providers are built with a single set of source files. This set of source files can be used to build binaries that will run in any environment.

If the MAPI SDK is installed in a 16-bit environment, a client can use only a 16-bit service provider.


Windows NT Service Client Applications

To enable client applications that are written as Windows NT services to operate with MAPI-compliant service providers, MAPI imposes several limitations and requirements. Simple MAPI, CMC, and MAPI clients have the following limitations:

  • They cannot allow a user interface.
  • They can only send messages through a tightly coupled message store and transport provider. In addition, MAPI clients can only send and receive messages using the Microsoft Exchange Server or another server-based transport provider. Because of identity and security issues between client applications and the MAPI spooler, most transport providers are not supported in a Windows NT service.

All client applications, whether or not they are implemented as Windows NT services, must call MAPIInitialize to initialize the MAPI libraries. A call to OleInitialize is also necessary to use the OLE libraries. Both MAPIInitialize and OleInitialize make calls to CoInitialize to initialize the Component Object Model (COM) libraries. Clients that are Windows NT services must set a special flag, MAPI_NT_SERVICE, in the ulFlags member of the MAPIINIT_0 structure that is passed to MAPIInitialize and in the ulFlags parameter that is passed to MAPILogonEx to inform MAPI of their special implementation.

Windows NT service clients written with the MAPI client interface have a few additional requirements:

  • They must set the MAPI_NO_MAIL flag in the call to MAPILogonEx. Other types of Windows NT service clients need not set a flag for logon because it is automatically set by MAPI.
  • They must add the service's account to the group of accounts called Administrators on the machine that the service is using. This is necessary for profile access. If the account does not belong to this Administrators group of accounts, the MAPIInitialize function will fail when called.

Note The requirement that the account belong to the Administrators group will be removed in a future release of Windows NT.

To handle messages in an initialization thread, a MAPI client that is implemented as a Windows NT service
  1. Calls MsgWaitForMultipleObjects when the main thread blocks.
  2. Calls the GetMessage, TranslateMessage, and DispatchMessage sequence of Windows functions to handle the message when MsgWaitForMultipleObjects returns the sum of the value of the nCount parameter and the value of WAIT_OBJECT_0, indicating that a message is in the queue.
To produce application log entries through asserts and error traces
  1. Use the debug version of MAPI.
  2. Add the following lines to the debug initialization file, MAPIDGB.INI:
    [General]

DebugTrace=1
EventLog=1


Environment Issues Affecting Service Providers

Service providers can only operate in the environment for which they are created. That is, a 16-bit service provider works only in 16-bit environments and a 32-bit service provider works only in 32-bit environments. To create a service provider that runs on any environment, there are two choices: create separate versions for each environment or use an approach known as single sourcing.

Single sourcing allows developers to use a special set of API functions provided by MAPI to reduce the amount of 16 bit-specific work. MAPI has ported a few dozen Win32 API functions to 16 bit. With these functions, 16-bit code can be written as if it were being written with the standard Win32 library of API functions. The code is compiled for the 16-bit environment using some special built-in support. All of the sample services installed with the MAPI SDK are single source services written using these APIs.

The environment used to install the MAPI SDK determines the set of client applications that a service provider can support. Service providers can be written to support clients that run on any of the following operating systems and environments:

  • Windows NT (32-bit)
  • Windows 95 (32-bit)
  • Win16

When the MAPI SDK is installed under Windows NT, a service provider can be created that can be used by 16-bit or 32-bit Windows NT clients. When the MAPI SDK is installed under Windows 95, a service provider can be created that can target 16-bit clients, Windows 95 clients, and in some cases, Windows NT clients. When the MAPI SDK is installed in a 16-bit environment, a service provider can be created that can target 16-bit clients only. Because MAPI does not support the 32-bit subset, Win32s, these service providers will only run in the 16-bit environment on Windows 3.1 or later.

Service providers should keep their future audience in mind when selecting an installation environment. If 16-bit clients are the only type of clients that will be using a service provider, a 16-bit environment for installation is appropriate. Likewise, if these clients are 32-bit clients, a 32-bit environment will work.

Some service providers, however, need to target clients that operate in all three operating environments: 32-bit Windows NT, 32-bit Windows 95, and 16-bit Windows. To target all environments, a service provider must operate in a 32-bit environment and must install both the 32-bit version of the MAPI SDK and the 16-bit version.

Service provider developers that are planning to target either Windows NT or Windows 95 should write their provider to be used by clients using both operating environments. Targeting both 32-bit environments is easy to do because the additional code required for the second environment is minimal.


Programming with CMC

This section contains conceptual information for programming with the Common Messaging Calls (CMC) application programming interface (API). You should understand this material before writing client applications that use the CMC APIs.


About CMC

The Common Messaging Calls (CMC) client interface is a set of ten functions that enables you to add simple messaging capabilities to your client applications quickly. For example, your client can send a message with a single CMC function call and receive a message with two CMC function calls.

Because CMC is built on top of the core MAPI subsystem, it shares the advantage of messaging system independence. The CMC API is especially valuable because it is also independent of the operating system and the underlying hardware used by the messaging system, providing a common messaging interface that can be used in virtually any environment. The CMC API is therefore a good choice for a messaging API when your client must run on multiple platforms and provide simple messaging functionality on each of these platforms.

Because CMC isolates clients from the complexities of MAPI, service providers, networking, and any other mechanisms which implement messaging, the remainder of this document will use the term "messaging system" to mean all of those things taken together. As far as a CMC client is concerned, the implementation layer underneath CMC is the messaging system that the client is using.

Although the Microsoft CMC implementation is built on top of a MAPI implementation, it is important to note that other implementations of CMC from other vendors might not be. In this document, "CMC" and "CMC implementation" mean "Microsoft's implementation of the CMC API using the MAPI API."

The CMC API was developed in conjunction with the X.400 API Association (XAPIA) standards organization and a group of e-mail vendors and users. It is supported on Microsoft Windows, MS-DOS, OS/2, Macintosh, and UNIX platforms. Because CMC is supported on several different platforms, a client application written to the CMC standard can be ported to other platforms. In contrast, MAPI is a Windows-only standard.

The CMC API supports three principal tasks: sending messages, retrieving messages, and looking up addressing information.

Note that these tasks do not have to be performed in isolation from each other. You can establish a session once with a call to the cmc_logon function and use the resulting CMC session for the duration of the user's interaction with the application. During that time, you can make many CMC calls to perform messaging tasks such as send messages, receive them, and make address book queries.

The CMC API works as a layer between a messaging-enabled application and the messaging system. The messaging system can support multiple messaging protocols, each using different messaging formats and protocols, for example, X.400, RFC 822, and Simple Mail Transfer Protocol. The design of the CMC interface specifies that its functions be independent of the messaging protocols. However, the API does enable developers to use extensions to invoke protocol-specific functions. For more information, see Using CMC Data Extensions.

An address book, a submission queue, and a receiving Inbox are the three messaging system components in the CMC API model.

Using the address book, the messaging-enabled application can look up information about users of connected messaging systems and can resolve users' names to actual addresses. Some messaging systems can also provide an interface enabling users to create recipient lists for messages or find out details about specific recipients.

The CMC implementation assigns a submission queue for each messaging-enabled application. By doing so, CMC provides each application with synchronous submission of messages to the underlying messaging system; once a call to send a message has returned, the calling application is guaranteed that the submission process has completed (although no guarantee is made about whether the message was successfully delivered). When the call has returned, the CMC implementation has all further responsibility for submitting the message to the underlying messaging system.

On the receiving side, an Inbox receives all messages for a user. The messaging system maintains Inboxes on behalf of messaging users. These Inboxes are accessible to users of messaging-enabled applications who have the proper permissions. With the CMC API, you can retrieve summaries of the contents of an Inbox, along with identifiers for the particular messages summarized. You can use these identifiers to select and retrieve individual messages.

The CMC API uses a fixed set of API functions, data structures, and data types. The API functions are the functions that your client calls to carry out messaging tasks. The data structures are the groupings of information that your client must provide to the CMC APIs, and are sometimes returned by the CMC APIs. The data types are basic elements that comprise the data structures. They each have a specific range of values and specific memory storage characteristics (for example, Boolean and floating point) and can have specific operations performed on them. For reference information, see Functions, Structures and Data Types, and Data Extensions.


Starting a CMC Session

CMC function calls occur within the context of a messaging session. Establish a session with a call to the cmc_logon function. The cmc_logon function checks the user's credentials for the messaging system, sets session attributes, and returns a session handle for use in later CMC calls. Session attributes include the character set and version number for the CMC API. Currently, the CMC API provides no support for sharing sessions among clients. End a session with a call to the cmc_logoff function.

You can convert the CMC session handles to MAPI session handles with the ScMAPIXFromCMC function. For example, you can convert the session handle returned from the cmc_logon function to an LPMAPISESSION value and use it to access the methods in the IMAPISession interface. This enables you to use CMC for the bulk of your messaging tasks without sacrificing access to MAPI functions. CMC session handles cannot be converted to Simple MAPI session handles. Clients that need both CMC and Simple MAPI functionality must maintain separate sessions for each.

You can also use the cmc_query_configuration function to determine logon identity and messaging options before calling the cmc_logon function.


Addressing Messages with CMC

You address messages with CMC by calling the cmc_look_up function to find addresses that you can then use with the cmc_send function. By calling cmc_look_up, you can search for names in the address book and resolve names into the addresses used by the underlying messaging system.

Both cmc_look_up and cmc_send make heavy use of the CMC_recipient structure. The cmc_look_up function uses it on input to receive the name of the recipient you are trying to look up. On output, cmc_look_up passes back an array of CMC_recipient structures that contain the results of the search. The cmc_send function uses a CMC_recipient structure to receive the address or addresses of the recipients of the message being sent.

To look up names and address information in the address book
  1. Establish a session either through the cmc_logon function or interactively by sending the CMC_LOGON_UI_ALLOWED flag value with the cmc_look_up function.
  2. Translate a user's display name (what the user sees) into a messaging address (what the underlying messaging system uses) by calling cmc_look_up. With this function, you can also request that the standard CMC address dialog box be displayed for the user to view recipient-specific details or create addressing lists.
  3. Release memory allocated by CMC by calling the cmc_free function.
  4. End the session by calling the cmc_logoff function.


Sending Messages with CMC

You send messages with CMC by building a CMC_message structure and passing it to the cmc_send function. Fill in the members of the CMC_message structure depending on the parameters used to invoke cmc_send. For example, if you pass the CMC_LOGON_UI_ALLOWED flag to cmc_send, then you don't need to provide a list of recipients, a subject line, or message text because CMC will query the user for that information.

When you call the cmc_send function, it must provide a session handle, a pointer to a CMC_message structure, any necessary flags, an optional user interface identifier if the flags include the CMC_LOGON_UI_ALLOWED flag, and optional extensions. Once cmc_send returns, you have no further responsibility for sending the message.

To send a message
  1. Establish a session with the messaging system either through the cmc_logon function or interactively by sending the CMC_LOGON_UI_ALLOWED flag value with the cmc_send function.
  2. Submit a message to the submission queue. Usually, a client application does so through the cmc_send function. If you call cmc_send, you must first create a CMC_message structure to pass to the cmc_send function. You can also call the more limited cmc_send_documents function to send a message; this function is primarily used to send messages or files from macro languages.
  3. End the session by calling the cmc_logoff function.


Receiving Messages with CMC

It is slightly more complex to receive messages with CMC than to send messages.

To receive a message
  1. Establish a session by calling the cmc_logon function.
  2. Retrieve a summary of Inbox information by calling the cmc_list function.
  3. Retrieve an individual message by calling the cmc_read function.
  4. Optionally, enable a user to act on the message in the Inbox (for example, delete it) by calling the cmc_act_on function.
  5. Release memory allocated by CMC by calling the cmc_free function.
  6. End the session by calling the cmc_logoff function.

There are a number of ways you can invoke the cmc_list function in order to control the sorts of messages listed by the API. For example, you can pass in the string "CMC: NDR" in the message_type parameter to obtain a list of nondelivery reports, or you can include the CMC_LIST_UNREAD_ONLY flag in the list_flags parameter to obtain a list of unread messages.


Handling Attachments with CMC

A CMC client application receives attachments in the form of an array of CMC_attachment structures on a message. Each element of this array specifies a file containing an attachment. The one exception to this rule is for embedded messages, which are received as a CMC message in the attachment extension.

CMC clients have no explicit method for distinguishing between OLE 1 and OLE 2 attachments. You should try opening the attachment as an IStorage object to determine whether the attachment is an OLE 2 object. If this fails, your client should try opening it as an OLE 1 IStream object. If both of these fail, the attachment should be treated as an ordinary data file.


Getting Information About the CMC Implementation

A client can get information about the CMC implementation by calling the cmc_query_configuration function. You must pass in an item code that specifies the type of configuration information for the cmc_query_configuration function to return. You must also pass in a pointer to a buffer where the cmc_query_configuration function can pass back the requested information. It is your responsibility to ensure that the buffer is large enough to hold data of the requested type.


Releasing Memory with CMC

In some circumstances, you will have to release memory that has been allocated by CMC. CMC provides a single function, cmc_free, for releasing memory that it has allocated. This memory is typically the result of a CMC function call. For example, the cmc_look_up function allocates an array of CMC_recipient structures to hold the results of an address book search. You are responsible for calling the cmc_free function on that array after it is no longer needed. To free memory allocated by CMC, pass a pointer to the memory to the cmc_free function.

A client should not try to free the memory itself. The memory is not guaranteed to be in a single contiguous block, so one call to an underlying memory management function — such as the C run time library function malloc — is not guaranteed to free all of the memory that CMC has allocated. A memory leak will result if you do this. The cmc_free function will make all the necessary memory management calls to properly free the memory CMC has allocated.


Ending a CMC Session

When a client no longer needs any message services, it should call the cmc_logoff function to end the CMC session that it established with the cmc_logon function. Depending on the nature of your client and whether it is possible to establish a CMC session without the user's assistance, it can be practical to close the session as soon as a group of messaging calls are finished. For other clients it is practical to establish one CMC session when the client starts and retain it until the client exits.


Using CMC Data Extensions

The data structures and functions defined by CMC can be expanded through the use of data extensions to add members to data structures and parameters to function calls.

Data extensions have two roles in CMC messaging. First, they are a mechanism to provide features not common across all messaging systems. Second, they enable extension of CMC in the future while also minimizing backward-compatibility issues. Use caution when using data extensions to take advantage of features specific to a messaging system. Reliance on specific features limits the portability of your client across messaging systems; also, such features might not be preserved properly when a message passes through multiple gateways in a mixed messaging network. If you do use data extensions, your code should test for the presence of the extensions and gracefully handle the absence of the extensions. Doing so will make your client portable to other CMC implementations.

Data extensions are grouped into extension sets. Extension sets have unique identifiers (defined constants) assigned to them that represent the set as a whole and that represent the individual extensions in the set. These identifiers are assigned by the X.400 API Association, which guarantees that there are no conflicts between identifiers in officially recognized extension sets. There are also provisions for allowing a CMC implementation to define its own data extensions without obtaining identifiers from the X.400 API Association. If this is done, clients that use those extensions might not be portable to other CMC implementations.

The CMC common extension set contains the function and data extensions that are common to most messaging systems but are not in the CMC base specification. The common extension set is identified by the CMC_XS_COM constant. Individual extensions in the common extension set are identified by constants with names that start with CMC_X_COM. For a full list of common extensions, see Data Extensions.

A generic data structure, CMC_extension, is the base from which these extensions are created. A CMC_extension structure consists of an item_code member identifying the extension, an item_data member containing the length of the extension data or the data itself, an item_reference member pointing to the location where the extension value is stored or that is NULL if there is no related item storage, and an extension_flags member containing a bitmask of extension flags. The item_code member identifies a particular extension and determines the meanings of values in the other members.

Extensions that are additional parameters to a function call can be either input or output parameters. That is, an extension can be passed either as an input parameter from your client application to CMC or as an output parameter from CMC to your client. If an extension is an input parameter, allocate memory for the extension structure and any other structures associated with the extension. If an extension is an output parameter, CMC allocates the memory for the extension result, if necessary, and you must free the allocated memory with a call to the cmc_free function.

To use a data extension
  1. Create a CMC_extension structure and fill in the members according to the extension you want to use.
  2. Pass a pointer to that structure in a call to a CMC function which can use it. The CMC function will use the information in the extension structure to enable additional functionality beyond the functionality defined for that CMC function in the X.400 API Association's CMC specification. The exact nature of the additional functionality is described in the documentation for the extension set you are using, which should be obtained from the extension set vendor.
  3. Retrieve any return values from the members of the CMC_extension structure if the CMC function uses the structure to pass values back to your client.


CMC Programming Examples

This section includes example code that illustrates the following common messaging operations:

  • Logging on and off and using cmc_query_configuration to get system information
  • Sending the same message using the cmc_send and cmc_send_documents functions
  • Listing, reading, and deleting the first unread message in the Inbox
  • Looking up a specific recipient and getting recipient details from the address book
  • Specifying use of the common extensions during a session logon

Error checking code has been deliberately left out of these examples for the sake of clarifying the use of the CMC functions themselves. Also, the way that an application recovers from errors is often dependent on the structure of the application, so it is unlikely that any error checking code in these examples would be of any use to other developers.


Logging On and Off: CMC Sample

The following code example demonstrates how you can log on and off and use cmc_query_configuration to get system information.

/* Local variables used */

CMC_return_code Status;
CMC_boolean     UI_available;   /* True if an interface is allowed */
CMC_session_id  Session;

/* Find out if user interface (UI) is available with this
   implementation before starting.*/

Status = cmc_query_configuration(
              0,                      /* No session handle         */
              CMC_CONFIG_UI_AVAIL,    /* See if UI is available.   */
              (void *)&UI_available,  /* Return value              */
              NULL);                  /* No extensions             */
    /* Error handling */

/* Log onto system using UI. */

Status = cmc_logon(
              NULL,                   /* Default service           */
              NULL,                   /* Prompt for user name      */
              NULL,                   /* Prompt for password       */
              NULL,                   /* Default character set     */
              0,                      /* Default UI ID             */
              CMC_VERSION,            /* Version 1 CMC calls       */
              CMC_LOGON_UI_ALLOWED |  /* Full logon UI             */
              CMC_ERROR_UI_ALLOWED,   /* Use UI to display errors. */
              &Session,               /* Returned session ID       */
              NULL);                  /* No extensions             */
    /* Error handling */

/* Do various CMC calls. */

/* Log off from the implementation. */

Status = cmc_logoff(
              Session,            /* Session ID                    */
              0,                  /* No UI will be used.           */
              0,                  /* No flags                      */
              NULL);              /* No extensions                 */
    /* Error handling */


Sending a Message: CMC Sample

The following code example demonstrates how you can send a message, using first the cmc_send and then the cmc_send_documents function.

/* Local variables used */

CMC_attachment  Attach;
CMC_session_id  Session;
CMC_message     Message;
CMC_recipient   Recip[2];
CMC_return_code Status;
CMC_time        t_now;

/* Build recipient list with two recipients.  Add one "To" recipient. */

Recip[0].name       = "Bob Weaver";       /* Send to Bob Weaver.      */
Recip[0].name_type  = CMC_TYPE_INDIVIDUAL;/* Bob's a person.          */
Recip[0].address    = NULL;               /* Look_up Bob's address.   */
Recip[0].role       = CMC_ROLE_TO;        /* He's a "To" recipient.   */
Recip[0].recip_flags= 0;                  /* Not the last element     */
Recip[0].recip_extensions = NULL;         /* No recipient extensions  */

/* Add one "Cc" recipient. */

Recip[1].name       = "Mary Yu";           /* Send to Mary Yu.        */
Recip[1].name_type  = CMC_TYPE_INDIVIDUAL; /* Mary's a person.        */
Recip[1].address    = NULL;                /* Look_up Mary's address. */
Recip[1].role       = CMC_ROLE_CC;         /* She's a "Cc" recipient. */
Recip[1].recip_flags= CMC_RECIP_LAST_ELEMENT;/* Last recip't element  */
Recip[1].recip_extensions = NULL;          /* No recipient extensions */

/*  Attach a file. */

Attach.attach_title = "stock.wks";         /* Original filename       */
Attach.attach_type  = NULL;                /* No specific type        */
Attach.attach_filename  = "tmp22.tmp";     /* File to attach          */
Attach.attach_flags   = CMC_ATT_LAST_ELEMENT;  /* Last attachment     */
Attach.attach_extensions = NULL;           /* No attachment extension */

/*  Put it together in the message structure. */

Message.message_reference   = NULL;     /* Ignored on cmc_send calls. */
Message.message_type        = NULL;     /* Interpersonal message type */
Message.subject             = "Stock";    /* Message subject          */
Message.time_sent           = t_now;    /* Ignored on cmc_send calls. */
Message.text_note           = "Time to buy";   /* Message note        */
Message.recipients          = Recip;      /* Message recipients       */
Message.attachments         = &Attach;    /* Message attachments      */
Message.message_flags       = 0;          /* No flags                 */
Message.message_extensions  = NULL;       /* No message extensions    */

/*  Send the message. */

Status = cmc_send(
              Session,         /* Session ID - set with logon call   */
              &Message,        /* Message structure                  */
              0,               /* No flags                           */
              0,               /* No UI will be used.                */
              NULL);           /* No extensions                      */
    /* Error handling */

/* Now do the same thing with the send documents call and UI. */

Status = cmc_send_documents(
              "to:Bob Weaver,cc:Mary Yu",      /* Message recipients  */
              "Stock",                         /* Message subject     */
              "Time to buy",                   /* Message note        */
              CMC_LOGON_UI_ALLOWED |
              CMC_SEND_UI_REQUESTED |
              CMC_ERROR_UI_ALLOWED,/* Flags (allow various UIs)  */
              "stock.wks",         /* File to attach             */
              "tmp22.tmp",         /* Filename to carry on attachment */
              ",",                 /* Multivalue delimiter       */
              0);                  /* Default UI ID              */
    /* Error handling */


Receiving a Message: CMC Sample

The following code example demonstrates how you can list, retrieve, and delete the first unread message in the Inbox.

/* Local variables used */

CMC_message_summary     *pMsgSummary;
CMC_message             *pMessage;
CMC_uint32              iCount;
CMC_session_id          Session;
CMC_return_code         Status;

/* Read the first unread message and delete it. */

iCount  = 5; /* Maximum number of messages to get summary info about. */

Status = cmc_list(
              Session,               /* Session handle                */
              NULL,                  /* List ALL message types.       */
              CMC_LIST_UNREAD_ONLY,  /* Get only unread messages.     */
              NULL,                  /* Starting at the top           */
              &iCount,               /* Input/output message count    */
              0,                     /* No UI will be used.           */
              &pMsgSummary,          /* Return message summary list.  */
              NULL);                 /* No extensions                 */
    /* Error handling */

Status = cmc_read(
              Session,                            /* Session ID       */
              pMsgSummary->message_reference,     /* Message to read  */
              CMC_MSG_AND_ATT_HDRS_ONLY,    /* Don't get attach files.*/
              &pMessage,                          /* Returned message */
              0,                                  /* No UI            */
              NULL);                              /* No extensions    */
    /* Error handling */

Status = cmc_act_on(
              Session,                           /* Session ID        */
              pMsgSummary->message_reference,    /* Message to delete */
              CMC_ACT_ON_DELETE,                 /* Message to read   */
              0,                                 /* No flags          */
              0,                                 /* No UI             */
              NULL);                             /* No extensions     */
    /* Error handling */

/* Free the memory returned by the implementation. */

Status = cmc_free(pMsgSummary);
Status = cmc_free(pMessage);

/* Do the same thing without the list call, because the read call can
   get the first unread message. */

Status = cmc_read(
             Session,                  /* Session ID                  */
             NULL,                     /* Read the first message.     */
             CMC_READ_FIRST_UNREAD_MESSAGE | /* Get first unread msg. */
             CMC_MSG_AND_ATT_HDRS_ONLY,/* Don't get attach files.     */
             &pMessage,                /* Returned message            */
             0,                        /* No UI                       */
             NULL);                    /* No extensions               */
    /* Error handling */

Status = cmc_act_on(
              Session,                           /* Session ID        */
              pMessage->message_reference,       /* Message to delete */
              CMC_ACT_ON_DELETE,                 /* Message to read   */
              0,                                 /* No flags          */
              0,                                 /* No UI             */
              NULL);                             /* No extensions     */
    /* Error handling */

/* Free the memory returned by the implementation. */

Status = cmc_free(pMessage);


Getting Recipient Details: CMC Sample

The following code example demonstrates how you can look up a specific recipient and get details on that recipient from the address book.

/* Local variables used */

CMC_session_id  Session;
CMC_recipient   *pRecipient;
CMC_recipient   Recip;
CMC_return_code Status;
CMC_uint32      cCount;

/* Look up a name to pick correct recipient. */

Recip.name       = "Bob Weaver";           /* Send to Bob Weaver.     */
Recip.name_type  = CMC_TYPE_INDIVIDUAL;    /* Bob's a person.         */
Recip.address    = NULL;                   /* Look_up Bob's address.  */
Recip.role       = 0;                      /* Role not used           */
Recip.recip_flags      = 0;                /* No flag values          */
Recip.recip_extensions = NULL;             /* No recipient extensions */

Status = cmc_look_up(
              Session,                     /* Session handle          */
              &Recip,                      /* Name to look up         */
              CMC_LOOKUP_RESOLVE_UI |      /* Resolve names using UI. */
              CMC_ERROR_UI_ALLOWED,        /* Display errors using UI.*/
              0,                           /* Default UI ID           */
              &cCount,                     /* Only want one back      */
              &pRecipient,                 /* Returned recipient ptr  */
              NULL);                       /* No extensions           */

/* Display details stored for this recipient. */

Status = cmc_look_up(
              Session,                    /* Session handle           */
              pRecipient,                 /* Name to get details on   */
              CMC_LOOKUP_DETAILS_UI |     /* Show details UI.         */
              CMC_ERROR_UI_ALLOWED,       /* Display errors using UI. */
              0,                          /* Default UI ID            */
              0,                          /* No limit on return count */
              NULL,                       /* No records returned      */
              NULL);                      /* No extensions            */

/* Free the memory returned by the implementation. */

cmc_free(pRecipient);


Using Common Extensions: CMC Sample

The following code example demonstrates how you can specify use of the common extensions during a session logon.

/* Local variables used */

CMC_return_code     Status;
CMC_session_id      Session;
CMC_extension       Extension;
CMC_extension       Extensions[10]; /* show how to handle multiple */
CMC_X_COM_support   Supported[2];
CMC_uint16          index;
CMC_boolean         UI_available;

/* Find out if the common extension set is supported, but
   COM_X_CONFIG_DATA support is not required. */

Supported[0].item_code =  CMC_XS_COM;
Supported[0].flags     =  0;

Supported[1].item_code =  CMC_X_COM_CONFIG_DATA;
Supported[1].flags     =  CMC_X_COM_SUP_EXCLUDE;

Extension.item_code       =   CMC_X_COM_SUPPORT_EXT;
Extension.item_data       =   2;
Extension.item_reference  =   Supported;
Extension.extension_flags =   CMC_EXT_LAST_ELEMENT;

Status = cmc_query_configuration(
              0,                         /* No session handle       */
              CMC_CONFIG_UI_AVAIL,       /* See if UI is available. */
              &UI_available,             /* Return value            */
              &Extension);               /* Pass in extensions.     */
    /* Error handling */

if (Supported[0].flags & CMC_X_COM_NOT_SUPPORTED)
    return FALSE;    /* Needed common extensions are not available. */

/* Log onto system and get the data extensions for this session.    */

Supported[0].item_code =  CMC_XS_COM;
Supported[0].flags =      0;

Supported[1].item_code =  CMC_X_COM_CONFIG_DATA;
Supported[1].flags =      CMC_X_COM_SUP_EXCLUDE;

Extension.item_code =         CMC_X_COM_SUPPORT_EXT;
Extension.item_data =         2;
Extension.item_reference =    Supported;
Extension.extension_flags =   CMC_EXT_REQUIRED | CMC_EXT_LAST_ELEMENT;

Status = cmc_logon(
              NULL,                   /* Default service             */
              NULL,                   /* Prompt for user name.       */
              NULL,                   /* Prompt for password.        */
              NULL,                   /* Default character set       */
              0,                      /* Default UI ID               */
              CMC_VERSION,            /* Version 1 CMC calls         */
              CMC_LOGON_UI_ALLOWED |  /* Full logon UI               */
              CMC_ERROR_UI_ALLOWED,   /* Use UI to display errors.   */
              &Session,               /* Returned session ID         */
              &Extension);            /* Logon extensions            */
    /* Error handling */
if (Supported[0].flags & CMC_X_COM_NOT_SUPPORTED)
    return FALSE;     /* Needed common extensions are not available, */
        /* the common data extensions will be used for this session. */

/* Example of how to free data returned from the CMC implementation in
   function output extensions.  */

for (index = 0; 1; index++) {
    if (Extensions[index].extension_flags & CMC_EXT_OUTPUT) {
        if (cmc_free(Extensions[index].item_reference) != CMC_SUCCESS){
            /* Handle unexpected error here. */
        }
    }
    if (Extensions[index].extension_flags & CMC_EXT_LAST_ELEMENT)
         break;
}

/* Do various CMC calls. */

/* Log off from the implementation. */

Status = cmc_logoff(
              Session,              /* Session ID                   */
              0,                    /* No UI will be used.          */
              0,                    /* No flags                     */
              NULL);                /* No extensions                */
    /* Error handling */


Programming with Simple MAPI

This section describes how and why you can use the Simple MAPI functions to add messaging functionality to your client application. The topics in this section cover the major areas of functionality that a Simple MAPI client needs to implement, such as:

  • Initializing your client so that it can use the Simple MAPI functions.
  • Creating messages.
  • Managing attachments.


About Simple MAPI

Simple MAPI provides a set of functions that enables you to add a basic level of messaging functionality to Microsoft Windows-based applications.

Because Simple MAPI is only intended for the Microsoft Windows environment and offers limited functionality, it is recommended primarily for backward compatibility with older client applications. You are encouraged to use CMC or MAPI for development of new clients whenever possible.You should link Simple MAPI clients with either the MAPI.DLL or the MAPI32.DLL library, depending on whether you are writing for 16-bit or 32-bit Windows platforms.

Simple MAPI contains 12 high-level functions that enable a client application to send, address, receive, and reply to messages. Messages sent using Simple MAPI can even include file attachments and OLE objects. Windows-based clients that are not primarily used for messaging, such as spreadsheets, word processors, or applications that require only basic messaging can use Simple MAPI to provide messaging functionality quickly and easily.

Simple MAPI has several features that make it a good option for clients that do not have extensive messaging needs:

  • By taking advantage of the MAPI subsystem, it maintains independence from the underlying messaging system and network.
  • It enables your client to define message types as well as the content of messages, and enables flexibility in the management of stored messages.
  • It includes an optional common user interface (dialog boxes), so with little effort you can make your clients look consistent with each other and with other Windows-based applications. Through these dialog boxes, your users can address, compose, and send messages. Using the common dialog boxes is not mandatory, however, so if your client does not need a user interface, it can call the Simple MAPI functions without displaying any dialog boxes.
  • Although designed to be called from C programs, your client can call the functions with little or no parameter modification from application-specific and standalone scripting packages such as Visual Basic, Actor, Smalltalk, and ObjectVision.

If you are writing a new client, you should implement it using MAPI or CMC. However, using MAPI involves learning about objects, interfaces, and the Component Object Model, and your client might only need the limited messaging functionality available with Simple MAPI. In this case, you should use CMC because it has the same functionality as Simple MAPI and it works with Microsoft Windows NT, Microsoft Windows for Workgroups 3.1, and Microsoft Windows 95. You should only use Simple MAPI for maintenance of older clients that were written using it.


Initializing a Simple MAPI Client

Before starting a Simple MAPI messaging session you need to initialize your client application. This involves checking the computer's WIN.INI file to determine if Simple MAPI is available, loading the correct dynamic link library (DLL) that contains the Simple MAPI functions, and setting a pointer to each function.

To initialize your client
  1. Determine that Simple MAPI is available by checking the [MAIL] section in the computer's WIN.INI file for the MAPI entry. This entry will have a value of 1 if Simple MAPI is installed, or 0 if uninstalled.
  2. Load the correct DLL for your operating system by calling the Windows LoadLibrary function as follows:
    hlibMAPI = LoadLibrary("MAPI.DLL");    // 16 bit clients
hlibMAPI = LoadLibrary("MAPI32.DLL");  // 32 bit clients

    The two DLLs for Simple MAPI are MAPI.DLL for 16-bit clients and MAPI32.DLL for 32-bit clients.

  3. Set the pointer variable to the actual address of the MAPILogon function as follows:
    lpfnMAPILogon = (LPFNMAPILOGON) GetProcAddress
    (hlibMAPI, "MAPILogon")))

Similarly defined constants exist for the other Simple MAPI functions, so you simply need to set the value of the function pointers using the Win32 function GetProcAddress as in the previous example.


Starting a Simple MAPI Session

Most MAPI calls are made in the context of a session, defined as an active connection between a client application and the MAPI subsystem. Each session uses a particular profile that specifies the set of available message services and the providers to manage those services. Before your client application can send or receive messages, it needs to log on and establish a session.

There are two types of sessions, temporary and persistent. A temporary session exists only for the lifetime of a single Simple MAPI call. A persistent session exists until the session is explicitly closed. Establishing a temporary session is referred to as implicit logon; establishing a persistent session is called explicit logon. You can use a persistent session for all calls that require the same set of providers and a temporary session for single calls that do not require the same context.

Note Some messaging systems can allow a limited number of sessions, so you must be able to handle a MAPI_E_TOO_MANY_SESSIONS return value. This value can be returned when a user is logged on to the system through an e-mail application and a mail-enabled application attempts to log on with a different identity.


Sharing Simple MAPI Sessions

Workgroup applications should all be able to work from the same profile without presenting logon or profile-selection dialog boxes when each application begins. A MAPI shared session is established once but can be used by other clients. Only one shared session can exist on a given computer at a time. The shared session can be used with any profile. If your client application must use a non-shareable session — that is, your client needs to be guaranteed that no other clients will use its session — then it must use the MAPILogon function in the MAPI API, which has a broader range of functionality than the Simple MAPI logon function.

By default, Simple MAPI attempts to use the shared session if it exists. If no shared session exists, Simple MAPI will create a new shared session when you call MAPILogon. If you log on with the MAPI_NEW_SESSION flag set, then Simple MAPI will create a new shared session regardless of whether one already exists.

The session handles returned to clients using a shared session are not the same. Each client, regardless of whether it is using a unique session or a shared session, has its own unique handle. Session handles are not valid across tasks, even when those handles represent the same shared session.


Explicit Logon with Simple MAPI

A client application logs on explicitly by calling the MAPILogon function. MAPILogon automatically opens the default address book for the Simple MAPI caller. When MAPILogon returns, the session is ready to service all messaging requests. The default message store provider is loaded and opened by the first Simple MAPI call that needs the message store.

The session handle produced by MAPILogon represents the MAPI session that you can use in further Simple MAPI calls. This session handle is passed to most Simple MAPI calls and can also be used with MAPI. The ScMAPIXFromSMAPI support method, prototyped in the MAPI.H file, converts a Simple MAPI session handle into a MAPI session object pointer. It is not possible to convert a Simple MAPI session handle into a CMC session handle. Clients needing both Simple MAPI and CMC functionality must maintain separate sessions for each.

Simple MAPI function calls produce return values that provide information about the success of a call. These return values are unsigned long values. Successful calls return the SUCCESS_SUCCESS value. Unsuccessful calls return error values starting with MAPI_E_, such as MAPI_E_INSUFFICIENT_MEMORY.


Implicit Logon with Simple MAPI

A client application logs on implicitly by using a 0 session handle when calling Simple MAPI functions. Not all of the Simple MAPI functions allow the session handle to be 0; these calls cannot be made outside of an established session. For example, the MAPIDeleteMail function can only delete a message from a pre-existing session; a 0 session handle causes MAPIDeleteMail to return an error value.

When the session handle is 0, Simple MAPI function calls use the flFlags parameter to determine how to create the temporary session. If flFlags is set to MAPI_NEW_SESSION, the call tries to establish a new session, either programmatically if possible or with a logon dialog box. If MAPI_NEW_SESSION is not set, the call tries to use the shared session. If the call cannot establish a temporary session or use the shared session, it will return an error value.

When the call completes, the state of the messaging system is as it was before the call was made. That is, the implicit session opened for the call is closed by the time the call returns.


Specifying a Profile During Simple MAPI Logon

A call to the MAPILogon function produces different results depending on whether you specify a profile name. Normally a profile name is required. If you specify NULL for the lpszProfileName parameter of the MAPILogon function, MAPI first checks for an existing shared session. If possible, the shared session is used. If there is no shared session or if it cannot be used, the call to MAPILogon will fail.

You can use this behavior to test for the presence of an existing shared session before creating one of your own.


Specifying Passwords with Simple MAPI

Whether a password is required for you to log on depends on the operating system which is running on the computer. If the operating system integrates messaging system credential checking into the initial system logon, you need not provide a password to the MAPILogon function. If not, a password is required from the user or from a cache location implemented by the client. Microsoft Windows NT and Microsoft Windows 95 do not require passwords for MAPILogon since the user's initial logon to the operating system suffices for both. Clients running with Microsoft Windows for Workgroups are required to provide a password for MAPILogon.


Requesting a Logon User Interface with Simple MAPI

A client application can log on either by displaying a logon dialog box to provide user interaction or by providing necessary credentials (profile name and password if necessary) programmatically. If you require user interaction, you can use the common dialog box provided by Simple MAPI or create your own. However, it is recommended that you use the standard MAPI dialog boxes whenever possible to promote a consistent look and ease of use.

The presence or absence of the MAPI_LOGON_UI value in the flFlags parameter of the MAPILogon function controls the logon dialog box display.

To force the dialog box to be displayed

Set MAPI_LOGON_UI in the flFlags parameter and set the lpszProfileName and lpszPassword parameters to NULL as follows:

flFlags |= MAPI_LOGON_UI;
MAPILogon ((ULONG) hWnd, NULL, NULL, flFlags, 0, &lhSession);

If you provide a value for lpszProfileName (and lpszPassword if necessary), MAPILogon attempts to establish a session without a user interface. Only if this attempt fails will MAPILogon display the logon dialog box for the user to enter new credentials.


Ending a Simple MAPI Session

To end a Simple MAPI session
  1. Call the MAPILogoff function to close a session when it is no longer needed.
  2. Call the MAPIFreeBuffer function to release any buffers that were allocated by Simple MAPI calls and returned to your client for its use. Calling MAPILogoff does not cause buffers allocated by Simple MAPI calls to be released. Your client has that responsibility.


Addressing Messages with Simple MAPI

Message headers form the "envelope" of a message. The message header contains all the information about the recipients of the message, as well as a subject for the message.

Addressing messages involves three major tasks:

  • Generating recipient lists for different recipient classes. There should be separate lists of addresses for primary recipients, carbon copy (CC) recipients, and blind carbon copy (BCC) recipients. See Generating Recipient Lists with Simple MAPI.
  • Checking names that the user enters against the address book to resolve them into actual addresses. See Checking Names with Simple MAPI.
  • Getting details about address book entries to help the user choose between ambiguous entries. See Getting Details About a User with Simple MAPI.

Creating a subject line is a simple matter of generating a text string containing the subject.


Generating Recipient Lists with Simple MAPI

A client application calls the MAPIAddress function to generate a list of recipients for a message. If some of the recipients are known already, for example when forwarding a message, you can pass in an initial array of MapiRecipDesc structures which the user can then modify.

MAPIAddress always displays a dialog box where the user can modify the list of recipients. If you need to generate a recipient list without presenting a dialog box, get recipients' names or addresses through some other means — by calling the MAPIResolveName function if necessary.

A successful call to the MAPIAddress function produces a buffer containing one or more MapiRecipDesc structures that you must release with the MAPIFreeBuffer function when the buffer is no longer needed.


Checking Names with Simple MAPI

Checking names is the process of using the MAPIResolveName function to take a recipient's display name — usually the recipient's real name or something derived from the real name — or partial display name and retrieve the address book entry corresponding to it.

To check names

Call the MAPIResolveName function. You can allow the display of address dialog boxes while resolving the name by setting the MAPI_DIALOG flag in the flFlags parameter. If the MAPI_DIALOG flag is not set and the recipient's display name resolves to more than one address book entry, MAPIResolveName will return the MAPI_E_AMBIG_RECIP error value.

If the MAPI_DIALOG flag is set, Simple MAPI will display a dialog box for the user to resolve the ambiguity. If the MAPI_AB_NOMODIFY flag is also set, the properties of addresses displayed in this dialog box will not be modifiable, even if the addresses are stored in the user's personal address book.

Like the MAPIAddress function, a successful call to MAPIResolveName produces a buffer containing one or more MapiRecipDesc structures that must be released with a call to the MAPIFreeBuffer function.


Getting Details About a User with Simple MAPI

The MAPIDetails function presents a dialog box to the user that displays the properties of an address book entry. This dialog box cannot be suppressed. Like the MAPIResolveName function, MAPIDetails supports the MAPI_AB_NOMODIFY flag to prevent modification of the properties displayed in the dialog box. MAPIDetails is most often used with this flag set when the user needs more information about an address in order to resolve an ambiguity. This function is most often used without the MAPI_AB_NOMODIFY flag set when the user needs to create or edit entries in the personal address book.


Displaying and Editing Addresses with Simple MAPI

The MapiRecipDesc structure, which describes a recipient, contains both the recipient's address and the recipient's "friendly name." The address, contained in the lpszAddress member, contains the address that the messaging system uses to deliver the message. This can take a number of forms depending on what type of address it is. All addresses are of the form [AddressType][E-mail Address]. For example, an internet address could be SMTP:jdoe@microsoft.com, while a fax gateway address could be FAX:206-555-1212.

The friendly name, stored in the lpszName member, typically contains the recipient's actual name or some variation of it. Whenever possible, the messaging system places a value in this member when a message is retrieved from a message store. However, not all addresses can be assigned a friendly name. For example, a fax gateway address might not correspond to a specific person, so the address book might not contain a name associated with that address. Similarly, the nature of internet addresses is such that the messaging system might not be able to determine a friendly name for messages that come into the system through an internet gateway; the address book cannot contain entries for every valid internet address, and the format of internet addresses does not mandate that a friendly name be attached to them.

You should display friendly names to the user when these names are available. When they are not, it is acceptable to display the actual address instead. When forwarding or replying to a message, you should never allow the user to edit the friendly name or address fields of a MapiRecipDesc structure that the messaging system has returned with a message. Both friendly names and addresses should be treated as indivisible entities.

When displaying a message to the user, make a distinction between different types of recipients that might be present in the message's lpOriginator and lpRecips members. The lpOriginator member contains the address and friendly name of the individual who sent the message. Display this recipient (note that the originator of a message is still called a recipient because both originators and actual recipients are described by MapiRecipDesc structures) so that the user is aware of this recipient's role.

Recipients stored in the lpRecips member can have one of four different roles. The ulRecipClass member of the MapiRecipDesc structure stores this information.

Role | Description
MAPI_TO | The recipient is a primary recipient of the original message.
MAPI_CC | The recipient received a carbon copy of the original message.
MAPI_BCC | The recipient received a blind carbon copy of the original message.
MAPI_ORIG | The recipient sent the message.

In practice, MAPI_BCC and MAPI_ORIG are less common than the others. MAPI_BCC should only occur if the user reading the message is the one who received a blind carbon copy. The semantics of MAPI_BCC are such that no one besides the originator and a MAPI_BCC recipient should ever know that the recipient received the message. MAPI_ORIG should only occur if the user sent a message to himself or herself.


Sending Messages with Simple MAPI

To compose a message, a client application either creates a new message, forwards an existing message, or replies to an existing message. The new message can contain new material. Replying to existing messages involves creating a new message and copying the contents of the original message to it. All new messages can specify a return receipt as well.

To send a message
  1. Create a MapiMessage structure to contain the message.
  2. Create one or more MapiRecipDesc structures describing the recipients of the message and place them in the lpRecips member of the MapiMessage structure.
  3. Create a text string containing the subject, if any, and place it in the lpszSubject member of the MapiMessage structure.
  4. Create a text string containing the message text, if any, and place it in the lpszNoteText member of the MapiMessage structure.
  5. Create an array of MapiFileDesc structures, if necessary, to contain any attachments and place it in the lpFiles member of the MapiMessage structure.
  6. Submit the message by calling the MAPISendMail function.

Sending messages can involve more or less effort on the part of your client, depending on the way you invoke various Simple MAPI functions to perform the above steps. For more information, see Controlled Sending of a Message: Simple MAPI Sample.

To create a new message
  1. Allocate a MapiMessage structure.
  2. Fill in the MapiMessage structure members with values appropriate for the message the user wants to send.
  3. Submit the MapiMessage structure to the messaging system by calling the MAPISendMail function.
To forward an existing message
  1. Retrieve the message by calling the MAPIReadMail function.
  2. Modify the message as appropriate for forwarding:
    • Put one or more new recipients' addresses in the message's lpRecips member.
    • Modify the subject line to indicate that the message has been forwarded.
    • Allow the user to edit the message text.
  3. Submit it to the messaging system by calling the MAPISendMail function.
To reply to a message
  1. Retrieve the message by calling the MAPIReadMail function.
  2. Modify the message as appropriate for replying:
    • Put the original sender's address into the lpRecips member.
    • Change the subject line to indicate that the message is a reply to an earlier message.
    • Allow the user to edit the message text.
  3. Submit the message to the MAPISendMail function.

When your client submits a message to MAPISendMail, it has the option of requesting a return receipt. Return receipts are automatically generated messages that senders receive to inform them that messages they sent, for which a return receipt was requested, were delivered successfully to the recipient. To request a return receipt, include the MAPI_RECEIPT_REQUESTED flag in the flFlags member of the MapiMessage structure:

// MapiMessage mymessage; declared and initialized elsewhere.
mymessage.flFlags |= MAPI_RECEIPT_REQUESTED;


Using the Subject with Simple MAPI

When a client application displays a message , the subject is simply a null-terminated string stored in the lpszSubject member of a MapiMessage structure.

When replying to or forwarding a message, modify the subject line. The subject of a reply to a message should begin with the string "RE:", or an appropriate localized equivalent. Similarly, forwarded messages should have subject lines that begin with "FW:" or an appropriate localized equivalent. If the subject line already begins with "RE:" or "FW:", do not add it again.


Handling Attachments with Simple MAPI

Simple MAPI handles attachments by means of an array of MapiFileDesc structures pointed to by the lpFiles member of a MapiMessage structure. The nFileCount member of the MapiMessage structure indicates the length of the array, with a value of 0 indicating there are no attachments. All Simple MAPI attachments are returned by means of temporary files.

Simple MAPI recognizes three types of attachments: data files, editable OLE objects, and static OLE objects. Use the values of the flFlags and lpszFileName members of a MapiFileDesc structure to determine the type of attachment it describes. OLE 2 attachments are identified by the .STG extension in the lpszFileName member. OLE 1 attachments are identified by the MAPI_OLE flag in the flFlags member. OLE 1 compliant clients which receive OLE 2 attachments can convert them by handling the OLE IStorage interface themselves or by using an OLE server to convert them to OLE 1. Embedded messages are data files that have the .MSG extension in the lpszFileName member.

Each attachment has an nPosition member that stores its position within the message. The position is an index into the message's lpszNoteText member — which can be treated as an array of characters. The attachment will appear at the character at its position in the message; that is, the attachment will be rendered instead of the character lpszNoteText[nPosition]. The special value -1 (0xFFFFFFFF) indicates that the attachment is not rendered in this way; in this case, the client receiving the message is responsible for providing the user with a way of accessing the attachment. Note that the position is a character position within the text note, not a byte offset into the text note. This is an important distinction when double byte character sets are in use.

Note The attachment should be rendered instead of the character stored in lpszNoteText[nPosition]. The actual value of lpszNoteText[nPosition] should be completely immaterial to the way the message is displayed to the user.

To add attachments to a message
  1. Allocate an array of MapiFileDesc structures, one for each attachment.
  2. Set the members of each array element to values appropriate for the data files or OLE objects that are being attached.
  3. Set the message's nFileCount member to the number of attachments.
  4. Set the message's lpFiles member to the address of the first element of the array of MapiFileDesc structures.
To handle attachments in a message your client has received
  1. Scan the attachments in the array of MapiFileDesc structures and note their character positions.
  2. When displaying the message text for the user, place graphic representations of data file attachments or OLE objects at the appropriate positions.
  3. Provide a mechanism for the user to interact with the attachments. You might choose to implement a point-and-click interface, or allow users to select actions such as saving and opening from a menu.


Message Options with Simple MAPI

Simple MAPI supports a few options for messages and for sending messages. Some of these options are accessed through members of the MapiMessage structure, and some through parameters of the MAPISendMail function.


About MapiMessage

The lpszMessageType member of the MapiMessage structure indicates the type of the message. The most common type is the interpersonal message, or IPM. A NULL value for lpszMessageType or a pointer to an empty string indicates an interpersonal message. Client applications can use this member to define their own message types. Be aware that not all messaging systems support message types other than IPM. Those messaging systems will ignore lpszMessageType.

The lpszMessageType member is also used to indicate when a message is a nondelivery report (NDR). The messaging system formats the nondelivery for a message type as REPORT. plus the message type plus .NDR. For example, if your client uses a message type of mytype, the nondelivery report for such a message will have REPORT.mytype.NDR as its lpszMessageType string. For clients that deal with multiple types of messages, your client can compare the last four characters of the lpszMessageType string against .NDR to determine whether the message is a nondelivery report. Naturally, you should not choose a string that ends in .NDR as an internal message type.

Note While nondelivery reports generated by MAPI follow this convention, nondelivery reports generated by transport providers for external mail delivery systems might not.

The flFlags member can be used to request a receipt and to detect the read or unread and sent or unsent status of a message. When sending a message, you can set the MAPI_RECEIPT_REQUESTED flag to request a receipt. When reading a message, you can test for the MAPI_UNREAD flag to determine whether the message has not yet been read. Similarly, you can test for the MAPI_SENT flag to determine whether the message has been sent. When saving a previously unsaved message, you should set the MAPI_UNREAD and MAPI_SENT flags as appropriate for the message.


About MAPISendMail

The MAPISendMail function supports options through its flFlags parameter. Your client application can set the following flags when sending a message.

Flag | Description
MAPI_LOGON_UI | Allows a logon interface if required. This flag should be set if you are using an implicit session.
MAPI_NEW_SESSION | Prevents Simple MAPI from using an existing shared session if one is present.
MAPI_DIALOG | Displays a dialog box which allows the user to create a message. This flag should be set if you do not have a MapiMessage structure already constructed, or if the user is composing a message interactively.


Simple MAPI Programming Examples

The code examples in this section are provided to illustrate in detail the concepts discussed earlier. Additional code examples can be found in the SMPCLI application included with the MAPI Software Development Kit (SDK). SMPCLI is not a typical Simple MAPI application because it exists solely to illustrate every Simple MAPI function. It is good for illustrating the use of all the Simple MAPI APIs, but it is not good for illustrating typical use of those APIs in real situations. See Sample Simple MAPI Client.

The following three examples show how a client application can send and receive messages with varying degrees of control. The first example sends a message very simply, leaving creation of the message's contents almost entirely up to Simple MAPI through user interaction. The second example takes more control over creation of the message and demonstrates how to use the MAPIResolveName function to check that addresses are valid before sending. The third example shows how to receive and display a message. Comments precede sections that benefit from explanation.


Sending a Message Simply: Simple MAPI Sample

This example shows the simplest way you can send a message. An essentially blank message is created and passed to the MAPISendMail function with parameters that cause Simple MAPI to use dialog boxes to create the content of the message. First, the client defines the variables it needs. Note that your client will not hard-code the attachment path name or filename in the MapiFileDesc structure.

// Example 1:
// Send a mail message containing a file and prompt for
// recipients, subject, and note text.

ULONG err;
MapiFileDesc attachment = {0,         // ulReserved, must be 0
                           0,         // no flags; this is a data file
                           (ULONG)-1, // position not specified
                           "c:\\tmp\\tmp.wk3",  // pathname
                           "budget17.wk3",      // original filename
                           NULL};               // MapiFileTagExt unused
// Create a blank message. Most members are set to NULL or 0 because
// MAPISendMail will let the user set them.
MapiMessage note = {0,            // reserved, must be 0
                    NULL,         // no subject
                    NULL,         // no note text
                    NULL,         // NULL = interpersonal message
                    NULL,         // no date; MAPISendMail ignores it
                    NULL,         // no conversation ID
                    0L,           // no flags, MAPISendMail ignores it
                    NULL,         // no originator, this is ignored too
                    0,            // zero recipients
                    NULL,         // NULL recipient array
                    1,            // one attachment
                    &attachment}; // the attachment structure

Next, the client calls the MAPISendMail function and stores the return status so it can detect whether the call succeeded. You should use a more sophisticated error reporting mechanism than the C library function printf.

err = MAPISendMail (0L,          // use implicit session.
                    0L,          // ulUIParam; 0 is always valid
                    &note,       // the message being sent
                    MAPI_DIALOG, // allow the user to edit the message
                    0L);         // reserved; must be 0
if (err != SUCCESS_SUCCESS )
    printf("Unable to send the message\n");


Controlled Sending of a Message: Simple MAPI Sample

This example shows how you can take more control over a message you send by specifying more of the contents of the message, validating addresses before sending, and by denying a sending interface to the user. Again, the client starts by defining its variables.

// Example 2:
// Send a mail message containing a spreadsheet and a short note
// to Sally Jones and copy the Marketing group. Don't prompt the user.

ULONG err;
MapiRecipDesc recips[2],     // this message needs two recipients.
             *tempRecip[2];  // for use by MAPIResolveName

// create the same file attachment as in the previous example.
MapiFileDesc attachment = {0,         // ulReserved, must be 0
                           0,         // no flags; this is a data file
                           (ULONG)-1, // position not specified
                           "c:\\tmp\\tmp.wk3",  // pathname
                           "budget17.wk3",      // original filename
                           NULL};               // MapiFileTagExt unused

The client then uses the MAPIResolveName function to generate MapiRecipDesc structures for the recipients of the message. It can create them directly, as in the previous example, but then no error checking is possible. Since this client is creating and sending the message without any interaction from the user, it is important to make sure the addresses are valid before sending the message.

// get Sally Jones as the MAPI_TO recipient:
err = MAPIResolveName(0L,            // implicit session
                      0L,            // no UI handle
                      "Sally Jones", // friendly name
                      0L,            // no flags, no UI allowed
                      0L,            // reserved; must be 0
                      &tempRecip[0]);// where to put the result
if(err == SUCCESS_SUCCESS)
    { // memberwise copy the appropriate fields in the returned
      // recipient descriptor.
        recips[0].ulReserved   = tempRecip[0]->ulReserved;
        recips[0].ulRecipClass = MAPI_TO;
        recips[0].lpszName     = tempRecip[0]->lpszName;
        recips[0].lpszAddress  = tempRecip[0]->lpszAddress;
        recips[0].ulEIDSize    = tempRecip[0]->ulEIDSize;
        recips[0].lpEntryID    = tempRecip[0]->lpEntryID;
    }
else
    printf("Error: Sally Jones didn't resolve to a single address\r\n");

// get the Marketing alias as the MAPI_CC recipient:
err = MAPIResolveName(0L,            // implicit session
                      0L,            // no UI handle
                      "Marketing",   // friendly name
                      0L,            // no flags, no UI allowed
                      0L,            // reserved; must be 0
                      &tempRecip[1]);// where to put the result
if(err == SUCCESS_SUCCESS)
    { // memberwise copy the appropriate fields in the returned
      // recipient descriptor.
        recips[1].ulReserved   = tempRecip[1]->ulReserved;
        recips[1].ulRecipClass = MAPI_CC;
        recips[1].lpszName     = tempRecip[1]->lpszName;
        recips[1].lpszAddress  = tempRecip[1]->lpszAddress;
        recips[1].ulEIDSize    = tempRecip[1]->ulEIDSize;
        recips[1].lpEntryID    = tempRecip[1]->lpEntryID;
    }
else
    printf("Error: Marketing didn't resolve to a single address\r\n");

Now, the client creates the message. Again, you should not hard-code the actual values of the MapiMessage structure's members.

MapiMessage note = {0, "Budget Proposal",
                   "Here is my budget proposal.\r\n",
                   NULL, NULL, NULL, 0, NULL,
                   2, recips, 1, &attachment};

Again, the client sends the message and records the return value. This time no user interface is displayed. After the MAPISendMail call, the MapiRecipDesc structures allocated by MAPIResolveName must be released.

err = MAPISendMail (0L,    // use implicit session.
                    0L,    // ulUIParam; 0 is always valid
                    &note, // the message being sent
                    0L,    // do not allow the user to edit the message
                    0L);   // reserved; must be 0
if (err != SUCCESS_SUCCESS )
    printf("Unable to send the message\n");
MAPIFreeBuffer(tempRecips[0]);  // release the recipient descriptors
MAPIFreeBuffer(tempRecips[1]);


Receiving a Message: Simple MAPI Sample

The following example shows how you can receive a message with Simple MAPI. For simplicity, this example assumes that a character interface is being used.

First, the client application defines needed variables and logs on to get a session handle. Unlike when sending a message, the Simple MAPI functions for reading messages can't log on implicitly and require an explicit session handle.

ULONG ReadNextUnreadMsg()
{
ULONG err;
LHANDLE lhSession;      // Need a session for MAPIFindNext.
CHAR rgchMsgID[513];    // Message IDs should be >= 512 CHARs + a null.
MapiMessage *lpMessage; // Used to get a message back from MAPIReadMail.
int i,                  // Ubiquitous loop counter.
    totalLength;        // Number of characters printed on a line.
err = MAPILogon(0L,               // ulUIParam; 0 always valid.
               "c:\\pst\\myprofil.pro",// Shouldn't hardcode this.
               NULL,              // No password needed.
               0L,                // Use shared session.
               0L,                // Reserved; must be 0.
               &lhSession);       // Session handle.
if (err != SUCCESS_SUCCESS)       // Make sure MAPILogon succeeded.
{
    printf("Error: could not log on\r\n");
    return(err);
}

Next, the client searches for the first unread message in the default folder in the store — probably the user's Inbox. Since there might not be any unread messages in the folder, the client first tests the return value from the MAPIFindNext function against MAPI_E_NO_MESSAGES before checking against SUCCESS_SUCCESS. If the call is successful, the client will have a valid message identifier to use to retrieve the first unread message.

// find the first unread message
err = MAPIFindNext(lhSession, // explicit session required
                   0L,        // always valid ulUIParam
                   NULL,      // NULL specifies interpersonal messages
                   NULL,      // seed message ID; NULL=get first message
                   MAPI_LONG_MSGID | // needed for 512 byte rgchMsgID.
                   MAPI_UNREAD_ONLY, // only get unread messages.
                   0L,        // reserved; must be 0
                   rgchMsgID);// buffer to get back a message ID.

if (err == MAPI_E_NO_MESSAGES) // make sure a message was found
{
    printf("No unread messages.\r\n");
    return(err);
}
if (err != SUCCESS_SUCCESS)    // make sure MAPIFindNext didn't fail
{
    printf("Error while searching for messages\r\n");
    return(err);
}

The client can now be sure it is safe to retrieve the message. However, it is still a good idea to check the return value from the MAPIReadMail function. If the call fails, the memory pointed to by the client's lpMessage pointer will not be accessible by the client. The client should not try to display a message at that location. Note that this example sets the MAPI_SUPPRESS_ATTACH flag so the returned message will not have any attachments in it and Simple MAPI will not create any temporary files for them.

// retrieve the message
err = MAPIReadMail(lhSession,   // Explicit session required.
                   0L,          // Always valid ulUIParam.
                   rgchMsgID,   // The message found by MAPIFindNext.
                   MAPI_SUPPRESS_ATTACH, // TO DO: handle attachments.
                   0L,          // Reserved; must be 0.
                   &lpMessage); // Location of the returned message.
if(err != SUCCESS_SUCCESS)      // Make sure MAPIReadMail succeeded.
{
    printf("Error retrieving message %s\r\n",rgchMsgID);
    return(err);
}

Now, the client can display the message. As expected, it begins by displaying the addressing information attached to the message before displaying the subject line and message text. When displaying the addressing information, it is best if you can display friendly names. However, since friendly names are not always available, you must verify that each recipient structure's lpszName member points to a valid string, and that the string is not a null string.

// Display the sender's name or address; use the friendly name
// if it is present.
if((lpMessage->lpOriginator->lpszName != NULL) &&
   lpMessage->lpOriginator->lpszName[0] != '\0')
    printf("From: %s\r\n",lpMessage->lpOriginator->lpszName);
else
    printf("From: %s\r\n",lpMessage->lpOriginator->lpszAddress);

Displaying the recipients' addresses is complicated by the need to avoid breaking a recipient's name or address across two lines. This code can be further improved by differentiating between recipients based on their ulRecipClass members so that they can be properly displayed as To, CC, or BCC recipients. As this code shows, handling recipient data can be the most complex part of reading a message.

// Display the recipients' names or addresses.  To Do: enhance
// this code to separate the recipients into lists of MAPI_TO,
// MAPI_CC, and MAPI_BCC recipients for separate display.
if(lpMessage->nRecipCount == 0)
    printf("Warning: no recipients present for this message\r\n");
else
    for(i = 0; i < lpMessage->nRecipCount; i++) // For each recipient...
    {
        // This code uses lstrlen to calculate the length of strings and
        // to validate that the strings have some content, since the
        // length is needed anyway. This avoids the more verbose checks
        // as were done for lpMessage->lpOriginator->lpszName earlier.

        // lpszT references a name or address; simplifies later code.
        // length is the length of the name or address.
        LPSTR lpszT = lpMessage->lpRecips[i]->lpszName;
        int length = lstrlen(lpszT);

        if(i == 0) // First recipient; need to do some initialization.
        {
            printf("Recipients:");
            totalLength = 11;      // since strlen("Recipients:") = 11.
        }

        // Decide whether to use the friendly name or the address.
        if(length == 0)
            length = lstrlen(lpszT=lpMessage->lpRecips[i]->lpszAddress);

        // Verify that the line has room for this name or address. If
        // not, print a CR LF pair to go to the next line.
        if(totalLength + length + 1 > LINE_WIDTH)
        {
            printf("\r\n");
            totalLength = 0;
        }

        printf(" %s",lpszT);      // Finally, print the name or address.
        totalLength += length + 1;// Maintain the line length.

        // If there are more addresses, separate them with semicolons.
        if(i < (lpMessage->nRecipCount - 1))
        {
            printf(";");
            totalLength++;
        }
    }

Now, the client displays the subject line and message text if they are present. Note that the message text can be printed with a simple call to the C library function printf. Since the message was read with the MAPI_SUPPRESS_ATTACH flag set, there will be no attachments in it.

// Display the subject and message body. Not printing anything for the
// subject is fine, but something should always be printed for the
// message body since it is the last thing that this function displays.
if(lpMessage->lpszSubject    != NULL &&   // Standard validity check
   lpMessage->lpszSubject[0] != '\0')
    printf("Subject: %s\r\n",lpMessage->lpszSubject);
if(lpMessage->lpszNoteText    != NULL &&  // Standard validity check
   lpMessage->lpszNoteText[0] != '\0')
    printf("Message Text:\r\n%s",lpMessage->lpszNoteText;
else
    printf("No message text.\r\n");

Finally, the client releases the memory that the MAPIReadMail function allocated for the message, closes the session, and returns a successful return value.

MAPIFreeBuffer(lpMessage);
MAPILogoff(lhSession,    // The session.
           0L,           // 0 always valid for ulUIParam.
           0L,           // No logoff flags.
           0L);          // Reserved; must be 0.
return SUCCESS_SUCCESS;  // Inform the caller of our success.
} // End of ReadNextUnreadMsg.


Objects and Interfaces

A MAPI object is a C++ object class or C data structure inherited from one or more MAPI interfaces, or collections of related functions. These collections of related functions are known to C++ developers as pure virtual functions. For a pure virtual function, MAPI supplies only the function prototype, not an implementation. It is expected that a client application, a service provider, or MAPI will provide this implementation by creating an object class inherited from the interface and conforming to the function descriptions documented in the MAPI Programmer's Reference. A MAPI interface can only be instantiated through an inherited class.

There are many different MAPI objects, each object inheriting from an interface that is ultimately inherited from IUnknown. IUnknown is the OLE Component Object Model (COM) base interface. It provides MAPI objects with a standard mechanism for communication and control. The Component Object Model dictates how object implementers handle issues such as memory management, parameter management, and multithreading. By conforming to this model, an object implementer adheres to a contract as specified by the interfaces included in the object.

Many MAPI interfaces are inherited directly from IUnknown while others are inherited indirectly through one of two other base interfaces: IMAPIProp for property management and IMAPIContainer for folder and address book access. Base interfaces are never implemented as separate, standalone objects; they are always implemented as part of other objects, objects that implement derived interfaces.

MAPI defines many types of objects, each implemented by one or more MAPI components. Objects implemented by clients are used by MAPI, by service providers, and by custom form components. Objects implemented by service providers are typically used by MAPI and by clients. Objects implemented by form library providers and form servers are used by other form components and by clients.


Component Object Model and MAPI

The Platform SDK documentation includes a comprehensive discussion of the rules for implementing objects that conform to the Component Object Model (COM). These rules address how to:

  • Design interfaces and objects.
  • Implement IUnknown.
  • Manage memory.
  • Handle reference counting.
  • Implement apartment threaded objects.

Although all MAPI objects are considered COM-based because they implement interfaces that inherit from IUnknown, MAPI deviates in some situations from the standard COM rules. This deviation allows developers more flexibility in their implementations. For example, a MAPI interface, like any COM interface, describes a contract between implementer and caller. Once the interface is created and published, its definition cannot and does not change. MAPI does not deviate from this description, but it relaxes the description somewhat. Implementers can choose to not implement particular methods, returning one of the following error values to the caller:

MAPI_E_NO_SUPPORT

MAPI_E_TOO_COMPLEX

MAPI_E_BAD_CHARWIDTH

MAPI_E_TYPE_NO_SUPPORT

The other deviations from the standard COM rules are described in the following table.

COM programming rule | MAPI variation
All string parameters in interface methods should be Unicode. | MAPI interfaces are defined to permit either Unicode or ANSI string parameters. Any method that has a string parameter also has a ulFlags parameter; the width of the string parameters is indicated by the value of the MAPI_UNICODE flag in ulFlags. Most MAPI interfaces to not support Unicode and return MAPI_E_BAD_CHARWIDTH when the MAPI_UNICODE flag is set.
All interface methods should have a return type of HRESULT. | MAPI has one method that returns a non-HRESULT value: IMAPIAdviseSink::OnNotify.
Callers and implementers should allocate and free memory for interface parameters using the standard COM task allocators. | All MAPI methods use the linked allocators MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer to manage memory for interface parameters. All MAPI implementations of interfaces defined by OLE, such as IStream, use the standard COM task allocators.
All out pointer parameters must explicitly be set to NULL when a method fails. | MAPI interfaces require that out pointer parameters either be set to NULL or remain unchanged when a method fails. All MAPI implementations of interfaces defined by OLE explicitly set out parameters to NULL on failure.
Implement aggregatable objects whenever possible. | MAPI interfaces are not aggregatable.


Objects and the MAPI Architecture

All of the objects defined by MAPI fall into one or more layers in the MAPI architecture. The client interface layer is made up of all the objects that a client application, form viewer, or form server can implement. The service provider interface layer contains the objects that a service provider of any type can implement. This layer includes objects implemented by address book, message store, transport, form library, and messaging hook providers. The layer that represents the MAPI subsystem is positioned between the client and service provider interface layers. The MAPI layer contains all of the objects that MAPI implements for clients or service providers to use.

The following illustration shows where each of the MAPI objects fits into the MAPI architecture. The objects are represented with the names of their derived interfaces. For example, an advise sink object is shown as IMAPIAdviseSink, the interface deriving from IUnknown that every advise sink object implements. The interfaces that bridge layers are either used or implemented by multiple components. Although the MAPI layer appears to separate the client and provider layers, implying that all communication must flow through MAPI, this is not the case. Clients can and do communicate directly to service provider objects.


Object Inheritance Hierarchy

All interfaces implemented by MAPI objects ultimately inherit from IUnknown, the OLE interface that enables objects to communicate. Most interfaces directly inherit from IUnknown, but some inherit from one of two other base interfaces: IMAPIProp and IMAPIContainer. The following illustration shows the complete inheritance hierarchy in MAPI.


Object Containment Hierarchy

The containment relationship between objects specifies the dependencies that some objects have on other objects for access. For a client application, access to particular objects enables access to others. In some cases, the containment relationship between objects implemented by a service provider follows a logical hierarchy. In other cases, it is arbitrary.

A client must obtain access to a MAPI session object before using many other objects, for example, service providers and the MAPI address book.

Message store containment is based on the hierarchical relationship between objects in the message store: the message store object itself, folders, messages, and attachments. Logically, attachments are contained in messages, messages in folders, and folders in the message store. The containment relationship matches this logical hierarchy. To gain access to a message, for example, a client must first access the folder in which the message is contained. Profiles and status objects are examples of a more arbitrary containment relationship. Both of these objects are available through the session.

With some objects, containers provide the only access. Attachments and recipients are examples of objects that are totally dependent on their containers. The only access to an attachment or a recipient is through the message to which it belongs. Other objects have alternate access paths. These objects are assigned binary identifiers, known as entry identifiers, by the service providers that create them. Entry identifiers can be used to access their objects directly, enabling clients to bypass the containment tree.

The following illustration shows the MAPI containment hierarchy. The session is at the top of the tree because it is through the session that a client gains access to all other objects. The next level includes the message store table, a table object that lists properties for all of the message store providers in the current session, and the address book to supply access to all of the address book providers. The message store table and address book are used to access the objects implemented by particular service providers, shown next, in containment order.


Objects Implemented by MAPI

MAPI implements several objects for use by client applications and service providers. The session object allows clients to use session services, to access tables, and to communicate with service providers. The address book object provides clients with integrated access to all of the different address book providers.

Multiple table and status objects are supplied by MAPI for clients to use for viewing and monitoring session and service provider information. For example, MAPI provides a profile table with information about all of the profiles that are installed on the computer and a message service table with information about all of the message services in the current profile. MAPI provides three different status objects: one that represents the overall subsystem, one for the MAPI spooler, and one for the integrated address book.

MAPI implements four different objects for managing the configuration of message services, service providers, and profiles. Both clients and service providers use provider administration and profile section objects; these objects enable them to configure service providers and access profile properties. Clients only use message service and profile administration objects, the objects that support the administration of message services and profiles.

MAPI provides two objects for service providers: a support object and a Tnef object. All service providers use one or more support objects; there are four different support object implementations. MAPI supplies an implementation to support configuration as well as specific implementations to support address book, message store, and transport providers. The Tnef object is used by transport providers that support the Transport Neutral Encapsulation Format (TNEF).

Two utility objects, table data and property data, are typically used by service providers. Table data objects help in the implementation of table objects; property data objects help to set and view property access and help in the implementation of IMAPIProp : IUnknown, the base property interface.

The following table summarizes the purpose for each object implemented by MAPI.

MAPI object | Description
Address book | Provides access to the integrated view of recipient information belonging to all of the address book providers in the active profile.
Message service administration | Provides access to message service information for configuration.
Profile administration | Provides access to profile information for configuration.
Profile section | A part of a profile used to describe a particular message service or service provider.
Property data | Maintains access to properties and helps implement IMAPIProp.
Provider administration | Provides access to service provider information for configuration.
Session | Represents a connection to underlying messaging systems and provides clients with access to MAPI resources.
Status | Provides access to the state of the MAPI subsystem, the address book, or the MAPI spooler.
Support | Provides service providers with help in handling client requests.
Table | Provides access to a summary view of object data in row and column format, similar to a database table.
Table data | Maintains access to underlying table data and implements table objects.
Tnef | Supports the use of the Transport Neutral Encapsulation Format (TNEF).

The following illustration shows the relationship between the objects that MAPI implements, the interfaces from which they inherit, and the components that use them.


About Client Objects

Standard messaging client applications implement only one object — an advise sink. Advise sinks inherit from the IMAPIAdviseSink : IUnknown interface and are used by MAPI and service providers for event notification. Some clients also implement progress objects to support the display of progress dialog boxes.

More complex clients that support custom forms implement another advise sink object and a few other objects, such as the message site object that inherits from the IMAPIMessageSite : IUnknown interface and the view context object that inherits from the IMAPIViewContext : IUnknown interface. The additional advise sink object inherits from the IMAPIViewAdviseSink : IUnknown interface.

The following table summarizes the MAPI objects implemented by standard messaging clients and by clients that support the viewing of custom forms.

Client object | Description
Advise sink | Provides a callback function for events that occur in the message store, address book, or the session.
Message site | Handles the manipulation of form objects.
Progress | Displays a dialog box to show the progress of an operation.
View advise sink | Provides callback functions for events that occur in a form.
View context | Supports commands for printing and saving forms and for navigating between forms.

The following illustration shows the relationship between these different client objects, the interfaces from which they inherit, and the MAPI components that use them.

Clients use many more objects than they implement. All clients use a session object to gain access to a wide variety of service provider objects and objects implemented by MAPI. Clients interact with service providers either indirectly, through the session, the address book, or the status objects supplied by MAPI, or directly through a variety of objects implemented by particular service providers. To make direct contact with address book providers, clients use address book containers, messaging users, and distribution lists. To access a message store provider directly, clients use the message store object, folders, messages, and attachments. When service providers support a status object, clients can use the status object to monitor the service provider's state.

Clients that support service provider and message service configuration use three objects implemented by MAPI: the message service administration object, profile administration object, and provider administration object. Clients that display custom forms use several form objects implemented by either a form library provider or a form server.


About Service Provider Objects

Service providers implement many objects, some that are used primarily by MAPI and some that are used by client applications. A few objects are implemented by all types of service providers; the rest are specific to a single provider type. The following table describes all of the service provider objects.

Service provider object | Description
Address book container | Contains recipient information for one address book provider in the active profile; address book providers can have one or more address book containers.
Attachment | Contains additional data, such as a file or OLE object, to be associated with a message.
Control | Enables or disables a button and initiates processing when the button is clicked.
Distribution list | Describes a grouping of individual message recipients.
Folder | Contains messages and other message containers.
Logon | Handles service provider event notification and client requests.
Messaging user | Describes an individual recipient of a message.
Message | Contains information that can be sent to one or more recipients with a messaging system.
Message store | Acts as a database of messages, organized hierarchically.
Provider | Handles service provider startup and shutdown.
Spooler hook | Performs special processing on inbound and outbound messages.
Status | Provides access to the service provider's state.
Table | Provides access to a summary view of object data in row and column format, similar to a database table.

All service providers implement a provider object and a logon object. Provider objects are strictly for bookkeeping; they are used by MAPI to control the start up and shutdown processes. Logon objects service some client requests indirectly. For example, the message store provider's logon object handles notification registration and requests to open message store objects.

Provider and logon objects implement a different interface depending on the type of service provider supplying the implementation. A message store provider implements the IMSProvider and IMSLogon interfaces in its provider and logon objects, an address book provider implements the IABProvider and IABLogon interfaces, and a transport provider implements the IXPProvider and IXPLogon interfaces.

Message hook providers implement spooler hook objects, or objects that filter inbound and outbound messages.

Service providers typically use only a few objects. Most frequently, they use a support object provided by MAPI that helps implement client requests. The support object is customized for the type of provider using it. For all service providers, the support object includes methods for handling event notification, displaying configuration properties, opening objects, and error handling. The rest of the methods are specific to its use; there are customized versions for address book, message store, and transport providers and for configuration support. For example, the address book support object displays details and custom recipient dialog boxes. The message store support object supports copy and move operations for folders and messages. The transport provider support object includes methods for facilitating interaction with the MAPI spooler.

Some service providers use table data and property data objects — utility objects implemented by MAPI. Table data objects enable service providers to manage the underlying data of a table. Property data objects enable service providers to set object and property access.

Transport providers that support the Transport-Neutral Encapsulation Format (TNEF) for transferring properties use a Tnef object implemented by MAPI that supports the ITnef interface. For more information, see Developing a TNEF-Enabled Transport Provider.


About Address Book Provider Objects

In addition to the standard provider and logon objects, address book providers implement address book containers, distribution lists, messaging users, tables, status objects, and controls. The following illustration shows these objects, their corresponding interfaces, and the MAPI components that use them.


About Message Store Provider Objects

Message store providers implement provider and logon objects as do all service providers. They also implement a message store object, folders, messages, attachments, and tables. As an option, some message store providers implement status objects.

The following illustration shows each message store object with its corresponding interface and the MAPI component that uses it.


About Transport Provider Objects

In addition to the standard provider and logon objects implemented by all service providers, transport providers are required to implement a status object. For the other service provider types, implementing a status object is optional. However, MAPI requires it for transport providers. Transport providers that support the downloading of message headers from a remote server also implement a folder and a table.

The following illustration shows each of the objects that transport providers can implement with their corresponding interfaces and indicates whether MAPI or a client is the object's user.


About Custom Form Objects

Objects for custom forms are implemented by three different components:

  • Form server
  • Form library provider
  • Form viewer

A form server is similar in functionality to an OLE compound document object application. It is an executable component that implements the form; it controls its display and the operations that a user can perform. MAPI launches a form server upon request when a user wishes to view a message with a message class that is displayed using a form supported by the form server. Form servers implement three objects: a form factory object that resembles the standard OLE class factory, a form advise sink for handling form-specific events, and the form itself.

A form library provider supplies clients with access to a form's property set, to its container, and to the object that links messages of a specific class with the server that can activate the form for that class. Form library providers implement three objects: a form information object, a form container, and a form manager for binding a message to the appropriate form server based on the message's class.

A form viewer is a component that is included in clients that support the display of custom forms from within their folder viewers. Form viewers are not independent MAPI components as are form library providers and form servers. They invoke form servers and provide context for them. Form viewers implement three objects: a message site, a view context, and an advise sink specific for handling view-specific events.

The following table describes all of the custom form objects.

Form object | Description
Form | Controls the display and operation of a custom form for viewing messages of a specific class.
Form advise sink | Handles notifications from the form viewer.
Form factory | Creates an instance of a form and allows its server to remain in memory.
Form container | Contains form information.
Form information | Contains messages and other message containers.
Form manager | Provides access to an integrated view of custom form information relating to all of the installed forms. Also matches message classes with corresponding form class identifiers.
Message site | Handles the manipulation of form objects from inside the client and provides access to a form manager object.
View context | Supports form commands for activating next and previous messages and for saving or printing.
View advise sink | Handles notifications from the form server.

The following illustration shows the relationship between custom form components, the objects and interfaces that they implement, and the components that are users of the objects. Notice that, unlike most other MAPI objects, the form object implements two interfaces that are not related by direct inheritance. When an object exposes multiple independent interfaces, a user of the object that has a pointer to one of the interfaces can retrieve a pointer to any of the other interfaces. This ability to navigate between an object's interface implementations is a feature of the QueryInterface method, one of the methods in the base interface IUnknown.


Using MAPI Objects

Clients and service providers use MAPI objects by calling the methods in their interface implementations. This is the only way that MAPI objects can be used; methods that are implemented by an object outside of a MAPI interface are not publicly accessible. Because all of an object's interfaces are related through inheritance, an object's user can call methods in either the base interface or one of the inherited interfaces as if they belong to the same interface.

When an object's user wants to make a call to a method and that object implements several interfaces related through inheritance, the user need not know to which interface the method belongs. The user can call any of the methods on any of the interfaces with a single pointer to the object. For example, the following illustration shows how a client application uses a folder object. Folder objects implement the IMAPIFolder : IMAPIContainer interface which inherits from IUnknown indirectly through IMAPIProp and IMAPIContainer. A client can call one of the IMAPIProp methods, such as GetProps, and one of the IMAPIFolder methods, such as CreateMessage, in the same way with the same object pointer. A client is not aware of or affected by the fact that these calls belong to different interfaces.

These calls translate into code differently depending on whether the client making the calls is written in C or C++. Before any call to a method can be made, a pointer to the interface implementation must be retrieved. Interface pointers can be obtained by:

  • Calling a method on a different object.
  • Calling an API function.
  • Calling IUnknown::QueryInterface on the target object.

MAPI provides several methods and API functions that return pointers to interface implementations. For example, clients can call the IMAPISession::GetMsgStoresTable method to retrieve a pointer to a table object that provides access to message store provider information through the IMAPITable : IUnknown interface. Service providers can call the API function CreateTable to retrieve a pointer to a table data object. When there is no function or method available and clients or service providers already have a pointer to an object, they can call the object's QueryInterface method to retrieve a pointer to another of the object's interface implementations.


Implementing MAPI Objects

MAPI objects are implemented using C++ classes or C data structures, depending on the language and the API set a client or service provider is using. Service providers are written in C or C++ with the MAPI service provider interface; client applications can use any of the three supported languages and the four supported client interfaces. If possible, clients and service providers using the object-oriented programming interface should use C++.

C++ is the preferred choice because MAPI is an object oriented technology and C++ lends itself more readily to object oriented development. The resulting code is simpler and more straightforward making it easier to maintain. Also, the MAPI documentation is written primarily for C++ developers; all of the syntax descriptions for the MAPI interface methods in the MAPI Programmer's Reference are in C++.

When a MAPI object is implemented, a client or service provider creates code for all of the interface methods, code for any private methods that are specific to the implementation, and code to support private data members for maintaining state information. The code for the interface methods must follow the specifications published by MAPI that document expected behavior.

There are many macros in the MAPIDEFS.H header file and OLE header files that clients and service providers in either language can use to help them with their definitions of MAPI objects. For example, there is a macro to define the methods of each of the MAPI interfaces. The macro to define the methods of IUnknown appears in MAPIDEFS.H as follows:

#define MAPI_IUNKNOWN_METHODS(IPURE)          \
    MAPIMETHOD(QueryInterface)                \
        (THIS_ REFIID riid, LPVOID FAR * ppvObj) IPURE;    \
    MAPIMETHOD_(ULONG,AddRef)  (THIS) IPURE;               \
    MAPIMETHOD_(ULONG,Release) (THIS) IPURE;   \


Implementing Objects in C++

C++ clients and service providers define MAPI objects by creating classes that inherit from the interfaces they are implementing. Each of the interface methods is public as are the constructor and destructor for the class. If the class has additional methods, they can be public or private, depending on the implementation. All data members are private.

The following example code shows how to define a C++ status object. The CMyMAPIObject class inherits from the IMAPIStatus : IMAPIProp interface. Many of the macros used in this example are defined in the OLE header file COMPOBJ.H.The first members of the class are the methods of the base interface, followed by the methods of the inherited interfaces in order of inheritance. Following the interface definitions are any additional methods, the constructor and destructor, and the data members.

class  CMyMAPIObject : public IMAPIStatus
{
public:
// Methods of IUnknown
    STDMETHODIMP QueryInterface (REFIID riid, LPVOID * ppvObj);
    STDMETHODIMP_(ULONG) AddRef ();
    STDMETHODIMP_(ULONG) Release ();

    MAPI_IMAPIPROP_METHODS(IMPL);
    MAPI_IMAPISTATUS_METHODS(IMPL);

// Other methods specific to CMyMAPIObject
    BOOL WINAPI Method1 ();
    void WINAPI Method2 ();

// Constructors and destructors
public :
    CMyMAPIObject () {};
    ~CMyMAPIObject () {};

// Data members specific to CMyMAPIObject
private :
    ULONG               m_cRef;
    CAnotherObj *       m_pObj;
};

To use an instance of the CMyMAPIObject class, C++ clients or service providers make a call to one of its methods as follows:

lpMyObj->ValidateState(ulUIParam, ulFlags);


Implementing Objects in C

Client applications and service providers written in C define MAPI objects by creating a data structure and an array of ordered function pointers known as a virtual function table, or vtable. A pointer to the vtable must be the first member of the data structure. In the vtable itself there is one pointer for every method in each interface supported by the object. The order of the pointers must follow the order of the methods in the interface specification published in the MAPIDEFS.H header file. Each function pointer in the vtable is set to the address of the actual implementation of the method. In C++, the vtable is set up automatically by the compiler. In C, it is not.

The following illustration shows how this works. The box on the far left represents a client that needs to use a service provider object. Through the session, the client obtains a pointer to the object, lpObject. The vtable appears first in the object followed by private data and methods. The vtable pointer points to the actual vtable containing pointers to each of the implementations of the methods in the interface.

The following sample code shows how a C service provider can define a simple status object. The first member is the vtable pointer; the rest of the object is made up of data members.

typedef struct _MYSTATUSOBJECT
{
    const STATUS_Vtbl FAR *lpVtbl;

    ULONG              cRef;
    ANOTHEROBJ        *pObj;
    LPMAPIPROP         lpProp;
    LPFREEBUFFER       lpFreeBuf;

} MYSTATUSOBJECT, *LPMYSTATUSOBJ;

Because this object is a status object, the vtable includes pointers to implementations of each of the methods in the IMAPIStatus : IMAPIProp interface as well as pointers to implementations of each of the methods in the base interfaces: IUnknown and IMAPIProp. The order of methods in the vtable match the specified order as defined in MAPIDEFS.H.

static const MYOBJECT_Vtbl vtblSTATUS =
{
    STATUS_QueryInterface,
    STATUS_AddRef,
    STATUS_Release,
    STATUS_GetLastError,
    STATUS_SaveChanges,
    STATUS_GetProps,
    STATUS_GetPropList,
    STATUS_OpenProperty,
    STATUS_SetProps,
    STATUS_DeleteProps,
    STATUS_CopyTo,
    STATUS_CopyProps,
    STATUS_GetNamesFromIDs,
    STATUS_GetIDsFromNames,
    STATUS_ValidateState,
    STATUS_SettingsDialog,
    STATUS_ChangePassword,
    STATUS_FlushQueues
};

Clients and service providers written in C use objects indirectly through the vtable and add an object pointer as the first parameter in every call. Every call to a MAPI interface method requires a pointer to the object being called as its first parameter. C++ defines a special pointer known as the this pointer for this purpose. The C++ compiler implicitly adds the this pointer as the first parameter to every method call. Since in C there is no such pointer; it must be explicitly added.

The following code fragment demonstrates how a client can make a call to an instance of MYSTATUSOBJECT:

lpMyObj->lpVtbl->ValidateState(lpMyObj, ulUIParam, ulFlags);


Implementing the IUnknown Interface

The methods of the IUnknown interface, implemented in every MAPI object, support interobject communication and object management. IUnknown has three methods: QueryInterface, AddRef, and Release. QueryInterface enables one object to determine if another object supports a particular interface. With QueryInterface, two objects with no prior knowledge of each other's functionality can interact. If the object implementing QueryInterface does support the interface in question, it returns a pointer to the implementation of the interface. If the object does not support the requested interface, it returns the MAPI_E_INTERFACE_NOT_SUPPORTED value.

When QueryInterface returns a requested interface pointer, it must also increase what is known as the new object's reference count. An object's reference count is a numeric value used to manage the object's lifespan. When the reference count is greater than one, the object's memory cannot be freed because it is actively being used. It is only when the reference count drops to zero that the object can be released safely.

The other two IUnknown methods, AddRef and Release, manage the reference count. AddRef increments the reference count while Release decrements it. All methods or API functions that return interface pointers, such as QueryInterface, must call AddRef to increment the reference count. All implementations of methods that receive interface pointers must call Release to decrement the count when the pointer is no longer needed. Release checks for an existing reference count, freeing the memory associated with the interface only if the count is 0.

Note Because AddRef and Release are not required to return accurate values, callers of these methods must not use the return values to determine if an object is still valid or has been destroyed.


Implementing IUnknown in C++

Implementing QueryInterface, AddRef, and Release in C++ is fairly simple. After some standard validation of the parameters passed in, an implementation of QueryInterface checks the identifier of the requested interface against the list of supported interfaces. If the requested identifier is among those supported, AddRef is called and the this pointer returned. If the requested identifier is not on the supported list, the output pointer is set to NULL and the MAPI_E_INTERFACE_NOT_SUPPORTED value is returned.

The following example shows how QueryInterface can be implemented in C++ for a status object, an object that is a subclass of the IMAPIStatus : IMAPIProp interface. IMAPIStatus inherits from IUnknown through IMAPIProp. Therefore, because these interfaces are related through inheritance, if a caller asks for any of them, the this pointer can be returned.

HRESULT CMyMAPIObject::QueryInterface (REFIID   riid,
                                       LPVOID * ppvObj)
{
    // Always set out parameter to NULL, validating it first
    if (IsBadWritePtr(ppvObj, sizeof(LPVOID)))
        return E_INVALIDARG;

    *ppvObj = NULL;

    if (riid == IID_IUnknown || riid == IID_IMAPIProp ||
        riid == IID_IMAPIStatus)
    {
        // Increment reference count and return pointer
        *ppvObj = (LPVOID)this;
        AddRef();
        return NOERROR;
    }

    return E_NOINTERFACE;
}

Note that this example is a 32-bit implementation; 16-bit implementations must include a call to ResultFromScode on their return statements to translate the 16-bit status code values to HRESULT values. For example, the final return statement would be recoded for 16-bit platforms as:

return ResultFromScode(E_NOINTERFACE);

The following code samples show how to implement the AddRef and Release methods for the CMyMAPIObject object. Because implementing AddRef and Release is so simple, many service providers choose to implement them inline. The calls to the Win32 functions InterlockedIncrement and InterlockedDecrement are to ensure thread safety. The memory for the object is freed by the destructor which is called when the Release method deletes the object.

ULONG CMyMAPIObject::AddRef()
{
    InterlockedIncrement(m_cRef);
    return m_cRef;
}

ULONG CMyMAPIObject::Release()
{
    // Decrement the object's internal counter
    ULONG ulRefCount = InterlockedDecrement(m_cRef);

    if (0 == m_cRef)
    {
        delete this;
    }

    return ulRefCount;
}


Implementing IUnknown in C

Implementations of QueryInterface in C are very similar to C++ implementations. There are two basic steps to the implementation:

  1. Validating parameters.
  2. Checking the identifier of the requested interface against the list of interfaces supported by the object and returning either the E_NO_INTERFACE value or a valid interface pointer. If an interface pointer is returned, the implementation should also call the AddRef method to increment the reference count.

The main difference between an implementation of QueryInterface in C and C++ is the additional first parameter in the C version. Because the object pointer is added to the parameter list, a C implementation of QueryInterface must have more parameter validation than a C++ implementation. The logic for checking the interface identifier, incrementing the reference count, and returning an object pointer should be identical in both languages.

The following code sample shows how to implement QueryInterface in C for a status object:

STDMETHODIMP STATUS_QueryInterface(LPMYSTATUSOBJ lpMyObj, REFIID lpiid,
                                   LPVOID FAR * lppvObj)
{

    HRESULT hr = hrSuccess;

    // Validate object pointer
    if (IsBadReadPtr(lpMyObj, sizeof(MYSTATUSOBJECT))
        || lpMyObj->lpVtbl != &vtblSTATUS )
    {
        hr = ResultFromScode(E_INVALIDARG);
        return hr;

    }

    // Validate other parameters
    if (IsBadReadPtr(lpiid, (UINT) sizeof(IID))
        || IsBadWritePtr(lppvObj, sizeof(LPVOID)))
    {
        hr = ResultFromScode(E_INVALIDARG);
        return hr;
    }

    // Set output pointer to NULL
    *lppvObj = NULL;

    // Check interface identifier
    if (memcmp(lpiid, &IID_IUnknown, sizeof(IID)) &&
        memcmp(lpiid, &IID_IMAPIProp, sizeof(IID)) &&
        memcmp(lpiid, &IID_IMAPIStatus, sizeof(IID)))
    {
        hr = ResultFromScode(E_NOINTERFACE);
        return hr;
    }

    // Interface is supported. Increment reference count and return
    lpMyObj->lpVtbl->AddRef(lpMyObj);
    *lppvObj = lpMyObj;
    return hr;
}

Whereas the implementation of AddRef in C is similar to a C++ implementation, a C implementation of Release can get more elaborate than a C++ version. This is because much of the functionality involved with freeing an object can be incorporated into the C++ constructor and destructor and C has no such mechanism. All of this functionality must be included in the Release method. Also, because of the additional parameter and its explicit vtable, more validation is required.

The following AddRef method call illustrates a typical C implementation for a status object:

STDMETHODIMP_(ULONG) STATUS_AddRef(LPMYSTATUSOBJ lpMyObj)
{
    LONG cRef;

    // Check to see if it has a lpVtbl object member
    if (IsBadReadPtr(lpMyObj,
            offsetof(MYSTATUSOBJECT, lpVtbl)+sizeof(STATUS_Vtbl *)))
    {
        return 1;
    }

    // Check size of vtable
    if (IsBadReadPtr(lpMyObj->lpVtbl,
         offsetof(STATUS_Vtbl, AddRef)+sizeof(STATUS_AddRef *)))
    {
        return 1;
    }

    // Check method
    if (STATUS_AddRef != lpMyObj->lpVtbl->AddRef)
    {
        return 1;
    }

    InterlockedIncrement(lpMyObj->cRef);
    cRef = ++lpMyObj->cRef;
    InterlockedDecrement (lpMyObj->cRef);

    return cRef;
}

A typical implementation of Release for a C status object follows. If after decrementing the reference count, it becomes zero, a C status object implementation should perform the following tasks:

  • Release any held pointers to objects.
  • Set the vtable to NULL, facilitating debugging in the case where an object's user has called Release yet continued to try to use the object.
  • Call MAPIFreeBuffer to free the object.
STDMETHODIMP_(ULONG) STATUS_Release(LPMYSTATUSOBJ lpMyObj)
{
    LONG cRef;

    // Check size of vtable
    if (IsBadReadPtr(lpMyObj, sizeof(MYSTATUSOBJ)))
    {
        return 1;
    }

    // Check if correct vtable
    if (lpMyObj->lpVtbl != &vtblSTATUS)
    {
        return 1;
    }

    InterlockedIncrement(lpMyObj->cRef);
    cRef = --lpMyObj->cRef;
    InterlockedIncrement (lpMyObj->cRef);

    if (cRef == 0)
    {
        lpMyObj->lpVtbl->Release(lpMyObj);
        DeleteCriticalSection(&lpMyObj->cs);

        // release IMAPIProp pointer
        lpMyObj->lpProp->Release(lpMyObj->lpProp);
        lpMyObj->lpVtbl = NULL;
        lpMyObj->lpFreeBuff(lpMyObj);
        return 0;
    }

    return cRef;

}


Implementing a Sample Object

Advise sink objects — objects that support the IMAPIAdviseSink : IUnknown interface — are an example of simple MAPI objects that are implemented by client applications for processing notifications. IMAPIAdviseSink inherits directly from IUnknown and contains only one method, OnNotify. Therefore, to implement an advise sink object, a client creates code for the three methods in IUnknown and for OnNotify.

The MAPIDEFS.H file defines an IMAPIAdviseSink interface implementation using DECLARE_MAPI_INTERFACE as follows:

#define      INTERFACE  IMAPIAdviseSink

DECLARE_MAPI_INTERFACE_(IMAPIAdviseSink, IUnknown)
{
    BEGIN_INTERFACE
    MAPI_IUNKNOWN_METHODS(PURE)
    MAPI_IMAPIADVISESINK_METHODS(PURE)
};

Clients implementing advise sink objects can define their interfaces in their objects manually or with the MAPI_IUNKNOWN_METHODS and MAPI_IMAPIADVISESINK_METHODS macros. Object implementers should use the interface macros whenever possible to ensure consistency across objects and to save time and effort.

Implementing the IUnknown::AddRef and IUnknown::Release methods is relatively simple because typically only a few lines of code are needed. Therefore, clients and service providers implementing objects can make their AddRef and Release implementations inline. The following code shows how to define a C++ advise sink object with inline implementations of AddRef and Release.

class  CMAPIAdviseSink : public IMAPIAdviseSink
{
public:
    STDMETHODIMP QueryInterface
                    (REFIID                     riid,
                     LPVOID *                   ppvObj);
    inline STDMETHODIMP_(ULONG) AddRef
                    () { InterlockedIncrement(m_cRef);
                         ++m_cRef;
                         InterlockedDecrement(m_cRef);
                         return m_cRef; };
    inline STDMETHODIMP_(ULONG) Release
                    () { InterlockedIncrement(m_cRef);
                         ULONG ulCount = --m_cRef;
                         InterlockedDecrement(m_cRef);
                         if (!ulCount)  delete this;
                         return ulCount;};
    MAPI_IMAPIADVISESINK_METHODS(IMPL);

    BOOL WINAPI AddConnection (LPMDB pMDBObj, ULONG ulConnection);
    void WINAPI RemoveAllLinks (LPMDB pMDBObj);

// Constructors and destructors
public :
    inline CMAPIAdviseSink  (CStoreClient * pStore)
                            { m_cRef = 1;
                              m_ulConnection = 0;
                              m_pStore = pStore;
                              AddRef;};
    ~CMAPIAdviseSink () {Release};

private :
    ULONG               m_cRef;
    CStoreClient *      m_pStore;
    ULONG               m_ulConnection;
};

In C, the advise sink object is made up of:

  • A pointer to a vtable that contains pointers to implementations of each of the methods in IUnknown and IMAPIAdviseSink.
  • Data members.

The following code sample shows how to define an advise sink object in C and construct its vtable.

// Object definition
typedef struct _ADVISESINK
{
    const ADVISE_Vtbl FAR *    lpVtbl;

    ULONG             cRef;
    STORECLIENT      *pStore;
    ULONG             ulConnection;

} ADVISESINK, *LPADVISESINK;

// vtable definition
static const ADVISE_Vtbl vtblADVISE =
{
    ADVISE_QueryInterface,
    ADVISE_AddRef,
    ADVISE_Release,
    ADVISE_OnNotify
};

After an object is declared in C, it must be initialized by setting the vtable pointer to the address of the constructed vtable as is shown following:

LPADVISESINK lpMyObj = NULL;

HRESULT hr = (*lpAllocateBuffer) (sizeof(ADVISESINK),
                 (LPVOID *)&lpMyObj);
lpMyObj->lpVtbl = &vtblADVISE;


Properties

A property is an attribute of a MAPI object. Properties describe something about the object, such as the subject line of a message or the address type of a messaging user. MAPI defines many properties, some to describe many objects and some that are appropriate only for an object of a particular type. Clients and service providers can extend MAPI's set of predefined properties by creating new, custom properties. Clients can define properties to describe new message classes, and service providers can define properties to expose the unique features of their messaging system.

Properties can be persistent or temporary. Properties that persist from session to session can be stored with their objects' data or in the profile. Temporary properties exist only for the duration of the current session.

Clients and service providers can show properties to users with either of the following components:

  • Table

    Tables provide users with a read-only view of some of the properties belonging to multiple objects. The data is displayed in row and column format, with each row representing an object and each column a property.

  • Property sheet

    Property sheets are tabbed dialog boxes that display related properties for a single object. Property sheets can provide read-only or read/write access to the data. Whether or not a user is allowed to make changes is up to the implementer of the property sheet.

The IMAPIProp interface is the primary interface for working with properties. All objects that support properties implement IMAPIProp. IMAPIProp includes methods for retrieving property values, copying properties, making changes and saving those changes, mapping between property names and their identifiers, and retrieving information about a prior error.

There are several data structures for describing properties and information about properties. The most commonly used structures are the SPropValue structure and the SPropTagArray structure. The SPropValue structure contains the three pieces of information that describe a property:

  • Data, or value, of the property.
  • Data type of the property's value, such as integer or Boolean.
  • Numeric value within a particular range that uniquely identifies the property and component responsible for maintaining it. For example, there is a range to hold message content properties defined by MAPI and another range to hold message content properties defined by a client for a custom message class.

The property type and identifier are combined into a single component called the property tag. Property tags are constants that can be used to easily refer to the property. Property tags for properties defined by MAPI are included in the MAPITAGS.H header file and in the ulPropTag member of an SPropValue structure. Clients and service providers use property tags to identify, retrieve, and update the corresponding properties.

The SPropTagArray structure is a counted array of property tags. Many of the methods in IMAPIProp and other interfaces use an SPropTagArray structure for describing properties.


About Property Tags

A property tag is a 32-bit number that contains a unique property identifier in bits 16 through 31 and a property type in bits 0 through 15 as shown in the following illustration.

Property tags are used to identify MAPI properties and every property must have one, regardless of whether the property is defined by MAPI, a client, or a service provider. MAPI defines a set of property tag constants for its properties in the MAPITAGS.H header file. These constants follow a naming convention for consistency and ease of use. There are two parts to every property tag: a PR_ prefix and one or more character strings that describe the contents of the property. Multiple character strings are separated by underscores. For example, the property tag for the address type of a message recipient is PR_ADDRTYPE and the entry identifier for the folder designated to receive a copy of every outbound message is PR_IPM_SENTMAIL_ENTRYID.

A few macros are available to help work with property tags, among them PROP_TYPE, PROP_ID, and PROP_TAG. PROP_TYPE extracts the property type from the property tag; PROP_ID extracts the identifier. PROP_TAG builds a property tag from a property type and identifier.


About Property Identifiers

A property identifier is a number that is used to indicate what a property is used for and who is responsible for it. Property identifiers are divided by MAPI into ranges; where an identifier falls in the range indicates its use and ownership.

The range of property identifiers runs from 0001 through FFFF. Property identifiers 0000 and FFFF are reserved in all cases, meaning that these identifiers must remain unused. The range for properties defined by MAPI runs from 0001 to 3FFF. The range 4000 to 7FFF belongs to message and recipient properties, and either clients or service providers can define properties in this range. Beyond 8000 is the range for what is known as named properties, or properties that have a name associated with their identifier. Clients can use named properties to customize their property set.

Service providers can define secure profile properties in the range 0x67F0 through 0x67FF. Secure profile properties are used for information that requires additional protection, such as passwords. These properties can be hidden and encrypted. Whether or not secure properties are included in the default list of properties returned by the IMAPIProp::GetPropList method depends on the provider's implementation. Usually these properties are not included. The IProfSect interface is used for accessing the properties of a profile section, secure properties included.

Some of the property ranges are restricted to transmittable properties or nontransmittable properties. Transmittable properties are transferred with a message; nontransmittable properties are not transferred with a message. Nontransmittable properties usually contain information that is of value only to clients and service providers operating with the current session. These properties would not necessarily be useful to another messaging system and another set of service providers. The concept of transmittable properties applies primarily to transport providers. To determine whether a property is transmittable or not, pass its property tag to the FIsTransmittable macro, defined in the MAPITAGS.H header file.

For a complete description of the identifier ranges, see List of Property Identifier Ranges.


About Property Types

Property types are constants defined by MAPI in the MAPIDEFS.H header file that indicate the underlying data type of a property value. All properties, whether they are defined by MAPI, by client applications, or by service providers, use one of these types.

Property types follow a similar naming convention to the one used for property tags. Many property types have both a single value and multivalue version. Single valued properties contain one value of its type such as a single integer or character string. The constant used to represent a single value property has two parts: the prefix PT_ and a string describing the actual type, such as LONG or STRING8.

Multivalued properties contain more than one value of its type. Unlike OLE variant arrays, every value in a multivalued property is of the same type. The constant used to represent multivalued properties is created by combining the MV_FLAG flag with the corresponding single value constant representing the base type. There are three parts: the prefix PT_ followed by MV_ followed by a string that describes the type. For example, the type for a property containing multiple integers is PT_MV_LONG and for multiple character strings is PT_MV_STRING8.

The following illustration shows the structure of an SPropValue structure to describe a multivalued integer, a property of type PT_MV_LONG. The Value member is expanded to include a count of the number of integer values in the property and a pointer to an array of those values.

Although support for multivalued properties is optional, MAPI recommends that clients and service providers support both types of properties because doing so enables greater interaction between MAPI-compliant components.

The following illustration lists all of the different property type constants, showing where they are stored in an SPropValue structure. The size of the Value member is dependent on the particular type. Notice that not all of the single-valued types have multivalued equivalents.

Clients and service providers working with a property need to follow two steps:

  1. Determine if the property is available or unavailable.
  2. If available, retrieve the property's value.

Sometimes a client or service provider need only check for the existence of a property; other times it is necessary to check for a specific value. For example, transport providers have three different courses of action for processing the PR_SEND_RICH_INFO property, a Boolean value that indicates whether or not a message should be transmitted with formatted text. If PR_SEND_RICH_INFO is set to TRUE, the transport provider transmits the formatted text. If it is set to FALSE, the formatted text is discarded before transmission. If PR_SEND_RICH_INFO is unavailable, the transport provider follows its default course of action, whatever that is for the particular provider.

MAPI defines a special property type, PT_UNSPECIFIED, that a client or service provider can use to retrieve a property when the property type is unknown.To retrieve a property without advance knowledge of its type, a client or service provider calls an object's IMAPIProp::GetProps method and passes a property tag made up of the property's identifier and the PT_UNSPECIFIED property type. GetProps returns an SPropValue structure for the property, replacing PT_UNSPECIFIED with the appropriate type. Service providers implementing GetProps are required to support PT_UNSPECIFIED.

Some MAPI objects support properties that are themselves objects. Object properties have the type PT_OBJECT. Instead of using IMAPIProp::GetProps to access these properties, clients and service providers typically access them by calling either:

  • The IMAPIProp::OpenProperty method, specifying the appropriate interface for access.

    – Or –

  • A method on the object supporting the property.

Because accessing the value of an object property involves using one of the interfaces for the object, GetProps is inappropriate. With GetProps, the caller accesses a property's value through an SPropValue structure. With IMAPIProp::OpenProperty, the caller retrieves a pointer to an interface that can access the object. OpenProperty can always be used to retrieve an object property. The other option, calling a method on the object, is not available with every object property.

For example, every folder supports two tables, a hierarchy table and a contents table. These tables are properties of the folder; their property tags are PR_CONTAINER_HIERARCHY and PR_CONTAINER_CONTENTS. Tables are objects that require the IMAPITable interface for access. A client can call the folder's IMAPIContainer::GetHierarchyTable method to access the hierarchy table, the folder's IMAPIContainer::GetContentsTable method to access the contents table, or the folder's IMAPIProp::OpenProperty method to access either table. To call OpenProperty, a client passes the property tag for the property as the first parameter and an interface identifier for the interface to be used for access as the second parameter. These parameters would be PR_CONTAINER_HIERARCHY or PR_CONTAINER_CONTENTS and IID_IMAPITable.

For a complete list of the single-valued and multivalued property types, see List of Property Types.


About String Properties

MAPI provides three different property types to describe string properties:

PT_TSTRING

PT_STRING8

PT_UNICODE

String properties are initially defined as PT_TSTRING. The PT_TSTRING property type conditionally compiles to one of the other string property types, depending on the operating system's character set. PT_STRING8 describes 8-bit null-terminated character strings in the ANSI format; PT_UNICODE describes double-byte null-terminated character strings.

Either a client or a service provider or both client and provider can choose to support Unicode character strings. It is not required. A client that supports only PT_STRING8 strings can operate with a provider that supports Unicode and vice versa. To allow this interoperability, clients and service providers pass a flag, the MAPI_UNICODE flag, to indicate that Unicode is supported in methods that involve the exchange of character strings.

For example, suppose a client supports Unicode and needs to retrieve the display name of a folder. All of the client's PT_TSTRING properties are compiled to type PT_UNICODE. When the client calls the folder's IMAPIProp::GetProps method to retrieve its PR_DISPLAY_NAME property, it passes the MAPI_UNICODE flag to request that the display name string be returned in the Unicode format.

Clients and service providers need to be aware that specifying a character set in a method call is only a request. Supporting one or both character sets is up to the implementer of the object. However, service providers are encouraged to support both character sets because it allows them to achieve more widespread distribution than providers that support only one set.

String properties can grow to be quite large as can binary properties — properties that use the property type PT_BINARY. To ease working with large properties, MAPI allows service providers setting these properties to enforce size limits. These limits can vary, depending on:

  • Whether the properties are being read or written.
  • The service provider implementing the IMAPIProp methods.
  • Runtime considerations such as memory constraints.
  • Character set translation issues.

Size limits can also be placed on string and binary properties when they are used in the column set of a table because it is sometimes impossible to make all of a large property's value visible. Many service providers truncate large string or binary properties that are used in tables to 255 bytes.

When a client calls an object's GetProps or SetProps method to work with a large string or binary property and the call fails because of the property size, the method returns the error value MAPI_E_NOT_ENOUGH_MEMORY. If it is GetProps that is failing for a specific property, the client can recover by calling IMAPIProp::OpenProperty and requesting the IStream interface for access by specifying IID_IStream as the interface identifier. With OpenProperty, the client can retrieve a large property using an interface such as IStream that is better suited for working with large properties.


Objects and Properties

Some properties are supported by many different types of objects. The following properties are examples of properties that are used by multiple objects:

  • PR_ENTRYID is a binary identifier used to open objects.
  • PR_OBJECT_TYPE is a constant used to identify the kind of object.
  • PR_DISPLAY_NAME is a character string used to describe an object to the user.

Other properties make sense for a single type of object. The following properties are examples of properties that apply to one type of object:

  • PR_MESSAGE_CLASS is a character string used to describe the type of a message.
  • PR_ROWID is an integer used to identify a row in a table.
  • PR_ATTACH_SIZE is an integer used to store the number of bytes in an attachment.

Still other properties are applicable only for a single type of object in a particular state. Properties of this type are typically message properties. When a message is first created, its set of properties is very small. As it is sent by a client to a recipient through the messaging system, the number of properties needed to describe the message increases. Some of these added properties appear only on the message as it is being delivered while others appear only on the message as it is being sent. Messages also have properties that are associated with the class to which they belong. Report messages, for example, have properties that are not supported by messages of other classes, such as note messages.

Every object has some required properties and may or may not have other optional properties. Required properties are properties that must exist on an object before the object can be successfully saved with its IMAPIProp::SaveChanges method. Clients or service providers using an object can depend on the availability of required properties after the SaveChanges call. That is, they can be sure that a call to the object's IMAPIProp::GetProps method or IMAPIProp::OpenProperty method to retrieve these properties will succeed.

Optional properties are properties that, depending on the object's implementer, may or may not be supported by an object. A client or service provider using the object cannot expect optional properties to be available through the GetProps or OpenProperty methods and to be set to valid values.

Lists of required and optional properties can be found in the documentation in various places. Descriptions of properties belonging to each of the message store and address book objects can be found in the discussion of the object's standard interface. For example, folder properties are discussed with IMAPIFolder and messaging user properties are discussed with IMailUser. Message properties, including report message properties, are described with IMessage and in About Message Properties. Properties belonging to each of the different types of tables are described in the appropriate Tables topic. For example, hierarchy table properties are described in Hierarchy Tables. Properties belonging to form servers are describing in Choosing a Form's Property Set.

When a client or service provider calls an object's GetProps method to retrieve several of its properties and one of these properties is unavailable, GetProps returns the warning MAPI_W_ERRORS_RETURNED. The call is considered to be successful because some of the properties were returned. When a client or service provider calls OpenProperty and the target property is unavailable, the method fails with the error MAPI_E_NOT_FOUND. It is important to check that a requested property is returned before attempting to work with it.

Depending on the object, the service provider supplying the implementation, and the property, a property can have read/write or read-only permission. Read/write permission allows a client or service provider using the property to change its value; read-only permission allows only the service provider owning the object to make changes.

To find out exactly which properties are currently set for an object, call IMAPIProp::GetPropList. GetPropList lets a caller find out what is available before an attempt to open a potentially nonexistent property is made. Because there is no standard set of properties that all objects of a specific type support, it is impossible to guess whether or not an object supports a particular property. Calling GetPropList eliminates the guess work.


Handling Property Errors

Rather than complete failure or success, the following IMAPIProp methods report partial success:

GetProps

SetProps

DeleteProps

CopyTo

CopyProps

GetProps reports partial success when it can retrieve at least one of the requested properties for an object. GetProps indicates partial success by returning the warning MAPI_W_ERRORS_RETURNED and placing information about the unavailable properties in the property value array pointed to by the lppPropArray parameter. An unavailable property's entry in this array contains PT_ERROR for the property type in the ulPropTag member and MAPI_E_NOT_FOUND or another appropriate error value for the Value member. For example, if a client calls a folder's GetProps method to retrieve three properties and the third is unavailable, the message store provider places PT_ERROR in the third property type in the property value array and MAPI_E_NOT_FOUND in the third property value.

The other IMAPIProp methods report partial success differently. These methods report partial success by returning S_OK and placing error information in an SPropProblemArray structure. Unlike the property value array in GetProps that contains data regardless of whether the method succeeded or failed, the property problem array in these methods exists only if there are errors and only if the caller has registered interest in learning about the errors. Callers must specify a valid SPropProblemArray pointer to register for error information.

When an error value is returned from SetProps, DeleteProps, CopyTo, or CopyProps, this indicates failure rather than partial success. The property problem array, if available, is not valid. Clients should not try to access data held in the structure nor should they try to free the structure itself. The appropriate response is to call IMAPIProp::GetLastError.

GetLastError is similar to the function of the same name provided in the Platform SDK. Both provide more detailed information about an error than is available with the return value. They both return information about the previous error that has occurred. The difference is that the Win32 GetLastError function reports on an error generated by the calling thread and the IMAPIProp::GetLastError method reports on an error generated by the current object. That is, if a client calls DeleteProps on a message and MAPI_E_NO_ACCESS is returned to indicate that the message is read-only, GetLastError returns data provided by the message.


Defining New Properties

In spite of the wealth of properties supplied by MAPI for use by clients and service providers, MAPI enables new properties to be created if necessary. Some of the valid scenarios for defining new public properties include a client creating properties to support a new message class and a service provider creating new properties to expose unique messaging system features. It is typically not valid for a service provider to define new properties for an existing MAPI object or message class. One of the primary benefits of using MAPI is that standard identifiers and formats for a large number of messaging system elements are set up, enabling users to seamlessly mix and match service providers. Service providers that use nonstandard properties do not work as well with other service providers.

Clients can create content properties for new message classes by:

  • Using property identifiers within a designated range for message class-specific content properties.

    – Or –

  • Using named properties.

The first option is preferable because not all service providers support named properties. MAPI defines two separate ranges for clients to use for new message class-specific content properties:

  • 0x6800 to 0x7BFF for transmittable properties
  • 0x7C00 to 0x7FFF for nontransmittable properties

Property identifiers must fall in predefined ranges to help prevent collisions between properties defined by different vendors or users. However, users of properties in these ranges cannot make assumptions as to the behavior of the properties. Every client that creates a new message class has access to these ranges; a property with identifier xxxx can mean one behavior for one message class and another behavior for another message class.

Named properties are used to guarantee a specific property is unique to a message class. Named property identifiers start in the 0x8000 range. Clients define one or more names and then call the message store's IMAPIProp::GetIDsFromNames method to associate an identifier with each name. Named properties can be used by clients or service providers to define new properties for any object only if the owner of the object supports named properties. Users of these properties call GetIDsFromNames and a related IMAPIProp method, GetNamesFromIDs, to map between a name and its identifier.

All properties, new or existing, must use the set of predefined property types. New property types cannot be added and existing types cannot be modified or deleted. Simple, small properties, such as single-character or 16-bit integer properties, can be stored in any appropriate type. For example, integers can be stored as ULONG and strings can be stored as PT_STRING8.

Use the PT_BINARY type to indicate a counted byte array. This property type is useful for extending the types of data that can be stored in an object. Bytes are transmitted in sequence and no assumptions are made about the meaning of the data. When a client application reads data out of such a property, the data is unchanged from how it was stored. The client must perform any necessary byte-swapping when moving data across CPUs.


Permissions for Objects and Properties

Access permission, or the set of permissable operations, can be a characteristic of MAPI objects and of individual properties supported by those objects. Object access is determined by an object's parent. For a message, its folder determines access permissions. For a messaging user or distribution list, its address book container makes this determination. When an object such as a message resides in two folders, the permissions for the two copies of the object can be different.

Clients using these objects can request the highest level of access permitted for the object by setting the MAPI_BEST_ACCESS flag on the IMAPISession::OpenEntry call. Depending on the service provider implementing the object, the client may or may not be granted the level of access necessary. Clients can determine the level of access that they were granted by calling the object's GetProps method to retrieve the PR_ACCESS property. However, because the service provider must dynamically generate the value for this property, it is recommended that clients retrieve it only when necessary.

To determine whether a container such as a folder, address book container, or distribution list allows modification, call its GetProps method to retrieve the PR_ACCESS_LEVEL property. Container level access affects clients in terms of how they display their user interfaces. It also impacts the implementers of objects within containers in terms of their user interface display and their general implementation.

Access to a particular property is determined by the property schema set up by MAPI for the object that owns the property. Property schemas specify the set of required and optional properties for an object and their access permission. Unlike object access which is determined by the object's parent, property access is global. Every object, regardless of the access requirements of the object's parent, has the same permissions for the property as determined by the schema.

When a property is read-only, it will always be available with a GetProps or OpenProperty call. However, depending on the implementation of the object supporting the property, there are two possible outcomes for the SetProps method for modifying a property and the DeleteProps method for removing it:

  • Fail and return MAPI_E_NO_ACCESS
  • Succeed with no action taken

Property and object access can also be retrieved or set using one of the interfaces that inherits from IMAPIProp, IPropData. MAPI provides an implementation of IPropData that is based on data in memory. Service providers can use IPropData to implement IMAPIProp in certain circumstances, such as for their status object or if they are using a database that does not have built-in transactions. IPropData works exclusively in memory, making it unnecessary to lock and unlock data.


Retrieving Properties

When a client or service provider retrieves a property from an object, the object makes available the property's value, type, and identifier. Clients and service providers can retrieve an object's properties by calling one of the following:

IMAPIProp::GetProps

IMAPIProp::OpenProperty

HrGetOneProp

The GetProps method is used to retrieve one or more properties that do not need a specialized or alternate interface for access. This implies that the properties available with GetProps are small, such as integers and Boolean values.

To retrieve multiple properties
  1. Allocate an SPropTagArray structure large enough to hold the number of properties to be retrieved.
  2. Set the cValues member of the SPropTagArray structure to the number of properties to be retrieved and set each aulPropTag member to the identifier and type, if possible, of one of the target properties.

    If the type is unknown, set it to PT_UNSPECIFIED.

    If both the type and the identifier are unknown, locate this information by calling IMAPIProp::GetPropList. GetPropList returns a property tag array with all of the object's supported properties.

    If only a property name is available, call IMAPIProp::GetIDsFromNames to access the associated identifier.

  3. Call IMAPIProp::GetProps to open the property or properties.

The OpenProperty method is used to open larger properties that require an alternate interface such as IStream or IMAPITable for access. OpenProperty is typically used to open large character string, binary, and object properties and can only open one property at a time. Callers pass in the identifier of the additional interface that is required as one of the input parameters.

Some of the common uses of OpenProperty include opening PR_BODY, the property that holds the body of a text-based message, PR_ATTACH_DATA_OBJ, the property that holds an OLE object or message attachment, and PR_CONTAINER_CONTENTS, the property that holds a folder or address book container contents table.

Depending on the property, a different interface is requested from OpenProperty. IStream, an interface that allows property data to be read and written as a stream of bytes, is typically used to access PR_BODY. Either IMessage or IStreamTnef can be used to access PR_ATTACH_DATA_OBJ. Embedded message attachments that are standard messages use IMessage whereas messages in the TNEF format use IStreamTnef. Because PR_CONTAINER_CONTENTS is a table object, it is accessed with IMAPITable.

To retrieve an attachment's PR_ATTACH_DATA_BIN property
  1. Call the OpenStreamOnFile function to open a stream for the file.
  2. Call the message's IMAPIProp::OpenProperty method to retrieve the PR_ATTACH_DATA_BIN property with the IStream interface. Set both the MAPI_MODIFY and MAPI_CREATE flags.
  3. Allocate a STATSTG structure and pass it in a call to the file stream's IStream::Stat method to determine its size. Another way to determine stream size is to call IStream::Seek with the flag STREAM_SEEK_END.
  4. Call the stream's IStream::CopyTo method to copy the data from the file's stream into the attachment stream.
  5. When the copy operation is finished, release both streams by calling their IUnknown::Release methods.

When IStream is used for property access, some service providers automatically send the size of the property back with the stream. Calling OpenProperty with the MAPI_DEFERRED_ERRORS flag can delay the opening of the property and the return of the stream size. If IStream::Stat is called to retrieve this size after OpenProperty with the MAPI_DEFERRED_ERRORS flag set, performance will be impacted because this sequence of calls forces an extra remote procedure call. To avoid the performance hit, clients can call any MAPI method between the calls to OpenProperty and to Stat.

The HrGetOneProp function, like OpenProperty, opens one property at a time. HrGetOneProp should only be used when the target object exists on the local machine. When the target object is not locally available, using HrGetOneProp can result in multiple remote procedure calls and a performance degradation.

Callers that need several properties can either call HrGetOneProp or OpenProperty in a loop or make one call to GetProps. Calling GetProps once is more efficient.

Note Secure properties are not automatically available with other properties in a GetProps, HrGetOneProp, or GetPropList call. Secure properties must be explicitly requested using their property identifiers.


Updating Properties

Clients and service providers can update a property value by calling:

  • An object's IMAPIProp::SetProps method to update the value of one or more of an object's properties.
  • The HrSetOneProp function to update only one property at a time.

    Use HrSetOneProp only if the target object is local; this function can cause performance degradation when used with remote objects.

The following procedure illustrates how to use SetProps to update the message class, or PR_MESSAGE_CLASS property, of a message.

To update the message class of a message
  1. Allocate an SPropValue structure for the message class and set its members as appropriate.
SPropValue spvMsgClass;
spvMsgClass.ulPropTag = PR_MESSAGE_CLASS;
spvMsgClass.Value.lpszA = "IPM.NewClass";
  2. Call the message's IMAPIProp::SetProps method to set the new message class.
hRes = lpMessage->SetProps(1, (LPSPropValue) &spvMsgClass, NULL);


Copying Properties

Clients and service providers can copy one or more of an object's properties with the following IMAPIProp methods and API functions:

  • The IMAPIProp::CopyTo method copies all of an object's properties to another object, optionally excluding selected properties. CopyTo is used for copying or moving any type of object.
  • The IMAPIProp::CopyProps method copies selected properties of an object. CopyProps is used mainly with messages. When a client creates a forwarded copy of a message or a reply, CopyProps handles copying the appropriate properties from the original message.
  • The PropCopyMore function copies a single property value from one location to another. Use PropCopyMore with caution. It is possible — when copying one value at a time — to allocate many small blocks of memory and cause memory to fragment.
  • The ScCopyProps function copies property values in bulk. ScCopyProps can copy property values that have been built from disjointed blocks of memory. It returns a new property array.
  • If the property array returned by ScCopyProps is to be stored on disk, use the ScRelocProps function to adjust the pointers. ScRelocProps should be called twice; once to adjust the addresses before writing the data operation and then again during the read operation. The ScRelocProps function assumes that the property value array was originally allocated in a single allocation.

The API functions described in the preceding list copy properties in memory rather than from one object to another object. These functions are presently supported, but might not be supported in a future release.


Saving Properties

Many objects support a transaction model of processing whereby changes to properties are not made permanent until they are committed at a later time. Whereas changes to properties are handled by the IMAPIProp::SetProps and IMAPIProp::DeleteProps methods, the commit step is handled by IMAPIProp::SaveChanges. It isn't until after a successful call to SaveChanges that the most recent version of an object's properties can be accessed.

When SaveChanges returns the error value MAPI_E_OBJECT_CHANGED, this is a warning that another client is simultaneously committing changes to the object. It is possible, depending on the provider implementing the object, for multiple clients to successfully open an object by calling its OpenEntry method with the MAPI_MODIFY flag set, giving them read/write access. The object that is returned from such an OpenEntry call is a snapshot of the storage data. Each subsequent attempt to change this data can overwrite the previous attempt.

Upon receiving MAPI_E_OBJECT_CHANGED from SaveChanges, a client has the option to:

  • Make a copy of the object to hold the changes.
  • Make another call to SaveChanges, specifying FORCE_SAVE.

Calling SaveChanges with the FORCE_SAVE flag overwrites the previous save and makes a client's changes permanent.


Named Properties

MAPI provides a facility for assigning names to properties, for mapping these names to unique identifiers, and for making this mapping persistent. Persistent name to identifier mapping ensures that property names remain valid across sessions.

To define a named property, a client or service provider makes up a name and stores it in a MAPINAMEID structure. Because names are made up of a 32-bit globally unique identifier, or GUID, and either a Unicode character string or numeric value, creators of named properties can create meaningful names without fear of duplication. Names are unique and they can be used without regard to the value of their identifiers.

To support named properties, a service provider implements two IMAPIProp methods — GetIDsFromNames and GetNamesFromIDs — to translate between names and identifiers and allows its IMAPIProp::GetProps and IMAPIProp::SetProps methods to retrieve and modify properties with identifiers in the named property range. The range for named property identifiers is between 0x8000 and 0xFFFE.

Any object that implements the IMAPIProp interface can support named properties. Address book providers that allow entries from other providers to be copied into their containers and message store providers that can be used to create arbitrary message types are required to supply this support. It is an option for all other service providers. Providers that do not support named properties return MAPI_E_NO_SUPPORT from the GetIDsFromNames and GetNamesFromIDs methods and refuse to set any properties with identifiers of 0x8000 or greater, returning MAPI_E_UNEXPECTED in the SPropProblem array.

Creating names for properties is one way for clients to define new properties for existing or custom message classes. Service providers can use named properties to expose unique features of their messaging systems. Yet another use for named properties is to provide an alternate way of referring to properties with identifiers below 0x8000.

For example, a client could use code similar to the following code to retrieve the names for all of an object's named properties:

LPSPropTagArray FAR *    lppPropTags = NULL;
LPGUID                   lpPropSetGuid = NULL;
ULONG FAR *              lpcPropNames;
LPMAPINAMEID FAR * FAR * lpppPropNames;

lpMAPIProp->GetNamesFromIDs (lppPropTags,
                             lpPropSetGuid,
                             0,
                             lpcPropNames,
                             lpppPropNames);

To request all names from the PS_PUBLIC_STRINGS property set, a client would replace the NULL in the property set parameter to PS_PUBLIC_STRINGS as follows:

LPSPropTagArray FAR *    lppPropTags = NULL;
LPGUID                   lpPropSetGuid = &PS_PUBLIC_STRINGS;
ULONG FAR *              lpcPropNames;
LPMAPINAMEID FAR * FAR * lpppPropNames;

lpMAPIProp->GetNamesFromIDs (lppPropTags,
                             lpPropSetGuid,
                             0,
                             lpcPropNames,
                             lpppPropNames);


Supporting Named Properties

Any object that implements the IMAPIProp interface can support named properties. Support for named properties is required for:

  • Address book providers that allow entries from other providers to be copied into their containers.
  • Message store providers that can be used to create arbitrary message types.

Named property support is optional for all other service providers. Service providers that do support named properties implement name-to-identifier mapping in two IMAPIProp methods, GetNamesFromIDs and GetIDsFromNames. Clients call GetNamesFromIDs to retrieve the corresponding names for one or more property identifiers in the over 0x8000 range and GetIDsFromNames to either create or retrieve the identifiers for one or more names.

Service providers that do not support named properties must:

  • Fail calls to IMAPIProp::SetProps to set properties with identifiers of 0x8000 or greater by returning MAPI_E_UNEXPECTED_ID in the SPropProblem array.
  • Return MAPI_E_NO_SUPPORT from the GetNamesFromIDs and GetIDsFromNames methods.


Property Names and Property Sets

The name of every named property has two parts:

  • A globally unique identifier, or GUID, that specifies a property set.
  • A Unicode character string or 32-bit numeric value.

Names of named properties are described using a MAPINAMEID structure. This structure contains a property set member, a member for specifying the name in either numeric or string format, and a member for identifying which format is used. Because the property set is part of the property's name, it is not optional. MAPI has defined several property sets for use by clients and service providers, but if an existing property set is inappropriate, a new property set can be defined. Clients and service providers can define their own property sets by calling UUIDGEN.EXE or the CoCreateGUID function to retrieve a unique property set identifier. CoCreateGUID is in the 32-bit DLL, OLE32.DLL, and the 16-bit DLL, COMPOBJ.DLL.Typically these property sets are created for custom client applications.

MAPI's property sets are represented by the following constants:

PS_MAPI

PS_PUBLIC_STRINGS

PS_ROUTING_EMAIL_ADDRESSES

PS_ROUTING_ADDRTYPE

PS_ROUTING_SEARCH_KEY

PS_ROUTING_DISPLAY_NAME

PS_ROUTING_ENTRYID

The PS_MAPI property set is reserved; it is used by service providers to generate names for properties with identifiers below the named property range. The PS_PUBLIC_STRINGS property set is used by clients for named properties of IPM messages and is the default property set for the Active Messaging Library Fields collection. One of the specific uses of the PS_PUBLIC_STRINGS property set is to map the summary properties of IPM.Document messages. Because named properties in the PS_PUBLIC_STRINGS property set appear in a client's user interface, nonvisible messages such as those that belong to the IPC message class should avoid creating named properties with this property set. Instead, they should create properties in the message class-specific range, 0x6800 through 0x7FFF.

The other property sets hold named properties describing recipients that are typically members of a routing list. Containing the same type of information as the properties that are associated with recipient list properties, properties in these property sets are understood by gateways to require mapping for a target messaging system. Because there are five types of information for describing properties, MAPI has defined five different property sets. A client sending a message that must include an address and address type for its routing list members assigns a named property for each member in the PS_ROUTING_EMAIL_ADDRESSES and PS_ROUTING_ADDRTYPE property sets. This ensures that the address and address type remain viable when sent to a foreign messaging system.


Mappings and Mapping Signatures

When a service provider supports named properties, each set of identifier and name pairs is referred to as a mapping. Service providers can support one mapping or several. That is, one message store provider, for example, can implement the GetIDsFromNames and GetNamesFromIDs methods for all of its message, folder, and message store objects to work with a single list of names and their corresponding identifiers. Another message store provider might have one list for every folder and the messages contained within it or implement a unique list for every message and every folder. Message store providers that use a unique mapping for every message must not allow named properties to appear in their folder contents tables because for a given property name, the property identifier will differ from message to message. MAPI recommends that providers keep it simple and operate with a single list for all of their objects including tables.

For every mapping, service providers must supply a mapping signature. A mapping signature is a binary value, usually a GUID, that uniquely identifies a set of property identifiers and their corresponding names. Mapping signatures are stored in an object's PR_MAPPING_SIGNATURE property. Service providers must change the value for their PR_MAPPING_SIGNATURE property whenever a change is made to the mapping that it represents. For example, PR_MAPPING_SIGNATURE must be updated if a new identifier is assigned to a name or a new name and identifier pair is added.

Clients working with the named properties of objects use the objects' PR_MAPPING_SIGNATURE properties in comparison and copy operations. To compare named property identifiers belonging to two objects, clients not using mapping signatures must call GetNamesFromIDs on both objects to retrieve the names for each of the identifiers. Using the mapping signatures of objects can render this call unnecessary. When two objects have the same value for their PR_MAPPING_SIGNATURE properties, they use the same mapping. Identifiers that use the same mapping can be compared directly. Service providers that implement IMAPIProp::CopyTo and CopyProps can also take advantage of an object's mapping signature. When copying named properties between objects, service providers can avoid the conversion step when the source and destination objects have the same mapping signature.


Handling Named Property Errors

When a request is made to IMAPIProp::GetIDsFromNames or IMAPIProp::GetNamesFromIDs that is too large for the implementer to handle, the error value MAPI_E_TOO_BIG is returned. Callers must divide their request into several requests, calling the appropriate method in a loop.

When a call results in partial success, such as when the request is for names that map to specific identifiers and one or more names cannot be found, GetNamesFromIDs returns MAPI_W_ERRORS_RETURNED and places PT_ERROR in the property type for the missing property in the property tag array.

Sometimes a client makes a call to GetNamesFromIDs that results in no properties being returned, such as when there are no properties in a specified property set or when all named properties are of a type excluded by the flags. Clients can expect service providers to:

  • Return S_OK.
  • Set the contents of the property tag array pointer to a newly allocated property tag array with its cValues member set to zero.
  • Set the contents of the MAPINAMEID structure array to NULL.
  • Set the contents of the count of MAPINAMEID structures to zero.


Transmitting and Copying Named Properties

Whenever a named property is sent, moved, or copied, the name remains constant but the identifier must change to adhere to the mapping of the destination object. The only exception to this rule is when the source and destination have the same mapping signature, making remapping unnecessary.

It is the responsibility of the transport provider to remap the names of transmitted named properties to appropriate identifiers that work at the destination. The sending transport provider cannot know what the correct mapping is at the destination; it must transmit the names and rely on the receiving transport provider to map them to identifiers that work. The MAPI implementation of TNEF handles the remapping of named properties for transport providers. Transport providers can either handle the remapping manually or use the TNEF implementation.

A similar remapping of named properties must occur when these properties are copied between message stores. However, because message store providers can retrieve the name to identifier mapping of the destination, they can remap the properties right away and not have to rely on the destination message store.


Tables

A MAPI table is a MAPI object that is used to view a collection of properties belonging to other MAPI objects of a particular type. MAPI tables are structured in a row and column format with each row representing an object and each column representing a property of the object. One of the properties usually included in each row is the PR_ENTRYID property, an identifier that can be used to open and modify the object.

Because rows contain property values, retrieving a row from a table is similar to getting a set of properties directly from the object that the row represents. Both operations result in the retrieval of a property value array. The main difference is in the handling of long string and binary properties. For inclusion in a table, some table implementers truncate these properties to 255 bytes. When retrieved directly from the object, the full value is always available.

Tables are implemented by address book and message store providers and by MAPI, depending on the type of table and the objects within it. A message store provider implements folders and a contents table for each folder that includes information about the messages in the folder. An address book provider implements address book containers and a hierarchy table that shows their organization. MAPI implements several different tables, some for use by client applications, some for use by service providers, and some for use by both. The status table is unique in that MAPI ultimately supplies the table, but the rows are comprised of contributions from all types of service providers in addition to MAPI.

The following illustration shows one of the frequent uses of a table in MAPI: to display the contents of a folder. On the right is a display of two messages as might appear in a typical messaging client application. The display contains four pieces of information about each message: the sender, the recipient, the subject, and the message text. Each piece of information corresponds to a property of the message.

On the left is a view of the contents table that includes these two messages. Whereas the contents table may have 10 rows because the folder has ten messages, with each row containing many more than three columns, this particular view is limited to only two rows and three columns.

The properties that make up the column set for the table view are:

PR_SENDER_NAME | Sender name
PR_ORIGINAL_DELIVERY_TIME | Date and time when the message was sent
PR_SUBJECT | Message subject line

Notice that the set of properties displayed in the message are not the same as the set of columns displayed in the table. The implementer of the table, in this case a message store provider, supplies a default set of columns in a default order. The client can modify this column set, requesting additional columns or rejecting default ones, and ask that they be ordered in a specific way. The client can also order the rows, sorting them according to the value of one or more columns.

There are two interfaces for working with tables:

  • IMAPITable : IUnknown gives clients and service providers a read-only view of the underlying data of the table, allowing them to view and change only the presentation. Multiple users can access the same data concurrently with IMAPITable. IMAPITable is implemented by MAPI and by service providers.
  • ITableData : IUnknown gives clients and service providers read/write access to the underlying data of the table, allowing them to make permanent changes. IMAPITable is implemented by MAPI and used primarily by service providers who access it by calling the CreateTable function.

    The ITableData implementation holds all the data for the table and any associated restrictions in memory, making it unsuitable for use with very large tables. Compound restrictions and complex operations such as categorization are unsupported.


Types of Tables

There are many different types of tables, each type differentiated by the information that it presents. Tables enable client applications and service providers to readily access and manipulate the important properties of many types of objects.

Some tables, such as contents tables, provide an alternative way of accessing properties. For example, a client can retrieve the subject of a message — its PR_SUBJECT property — either directly from the message by calling its IMAPIProp::GetProps method or through the message's contents table. Other tables provide the only way to access object properties. For example, a client cannot access an attachment's PR_ATTACH_METHOD property by calling IMAPIProp::GetProps; it must always retrieve the attachment table of the message to which it is attached. PR_ATTACH_METHOD is a required column in all attachment tables.

A table view can be static or dynamic. With a static table view, changes to the underlying data do not cause the view to be updated. Once the view has been instantiated, it does not change. Users of static tables can be informed of changes to data through table notifications. A dynamic table view is updated when changes are made to the data. There are two types of dynamic tables: one that updates the columns of each row, but the rows remain static and one that updates both the columns and rows. This latter type of table always reflects the underlying data exactly.

Tables have a default column set, the minimum set of columns that a client or service provider can expect to see when retrieving rows from a table that has not yet been affected by an IMAPITable::SetColumns call. Clients and service providers can add columns to or remove columns from this default set by calling the SetColumns method. Changes can be made either statically or dynamically, following a client request. Not all tables support dynamic column set modification.

The MAPI tables and their implementers and users are:

Table | Implementers
Attachment | Implemented by message store providers. Used by clients and transport providers.
Contents | Implemented by message store and address book providers. Used by clients.
Display | Implemented by MAPI and service providers. Used by MAPI and service providers.
Hierarchy | Implemented by message store and address book providers. Used by clients.
Message service | Implemented by MAPI. Used by clients.
Message store | Implemented by MAPI. Used by clients.
One-off | Implemented by address book providers. Used by MAPI.
Outgoing queue | Implemented by message store providers. Used by MAPI spooler.
Profile | Implemented by MAPI. Used by clients.
Provider | Implemented by MAPI. Used by clients.
Receive folder | Implemented by message store providers. Used by clients.
Recipient | Implemented by message store providers. Used by clients and transport providers.
Status | Implemented by MAPI and service providers. Used by clients.


Attachment Tables

An attachment table contains information about all of the attachment objects that are associated with a submitted message or a message under composition. Only attachments that have been saved through a call to the message's IMAPIProp::SaveChanges method are included in the table. Attachment tables are implemented by message store providers and used by client applications and transport providers.

An attachment table can be accessed by calling:

  • IMessage::GetAttachmentTable.

    – Or –

  • IMAPIProp::OpenProperty, requesting the PR_MESSAGE_ATTACHMENTS property.

Attachment tables are dynamic.

Message store providers are not required to support sorting on their attachment tables. If sorting is not supported, the table must be presented in order by rendering position — the PR_RENDERING_POSITION property.

Message store providers are also not required to support restrictions on their attachment tables. Providers that do not support restrictions return MAPI_E_NO_SUPPORT from their implementations of IMAPITable::Restrict and IMAPITable::FindRow.

Attachment tables can be small; there are only four columns in the required column set:

PR_ATTACH_NUM

PR_INSTANCE_KEY

PR_RECORD_KEY

PR_RENDERING_POSITION

PR_ATTACH_NUM is nontransmittable and contains a value for uniquely identifying an attachment within a message. This property is often used as an index into the rows of the table. PR_ATTACH_NUM has a short lifespan; it is only valid while the message containing the attachment is open. Its value is guaranteed to remain constant as long as the attachment table is open.

PR_INSTANCE_KEY is required in nearly every table. It is used to uniquely identify a particular row.

PR_RECORD_KEY is commonly used to uniquely identify an object for comparison purposes. Unlike PR_ATTACH_NUM, PR_RECORD_KEY has the same scope as a long-term entry identifier; it remains available and valid even after the message is closed and reopened. For more information about the use of record keys in MAPI, see Record and Search Keys.

PR_RENDERING_POSITION indicates how an attachment should be displayed in a plain text message. It can be set to an offset in characters, with the first character of the message content as stored in the PR_BODY property being offset 0, or to -1 (0xFFFFFFFF), indicating that the attachment should not be rendered within the message text at all. Not setting PR_RENDERING_POSITION is also an option.

When an attachment table is sorted by rendering position, the message store provider treats it as a signed value (PT_LONG). Therefore, attachments with rendering positions of -1 are sorted before attachments with rendering positions that reflect valid offsets.

For more information about rendering an attachment in a plain text message, see Rendering an Attachment in Plain Text.

For information about rendering an attachment in formatted text such as Rich Text Format (RTF), see Rendering an Attachment in Formatted Text.

Some of the properties message store providers commonly include in an attachment table because they are easy to compute or retrieve are:

PR_ATTACH_ENCODING | PR_ATTACH_EXTENSION
PR_ATTACH_FILENAME | PR_ATTACH_LONG_FILENAME
PR_ATTACH_PATHNAME | PR_ATTACH_LONG_PATHNAME
PR_ATTACH_METHOD | PR_ATTACH_TAG
PR_CREATION_TIME | PR_ATTACH_TRANSPORT_NAME
PR_DISPLAY_NAME | PR_LAST_MODIFICATION_TIME


Contents Tables

A contents table contains information about objects in a MAPI container. Address book providers implement contents tables for each of their containers and message store and remote transport providers implement contents tables for their folders. The contents table of an address book container lists information about its messaging user and distribution list objects while the contents table of a folder lists information about its messages. Contents tables are used primarily by client applications.

There are two types of folder contents tables:

  • Standard contents tables contain standard messages — messages that can be transmitted and made visible to a user.
  • Associated contents tables contain hidden, non-transmittable information created by a client for a specific purpose, such as to store an alternate representation of a standard message. Associated information is created by passing the MAPI_ASSOCIATED flag to the IMAPIFolder::CreateMessage call.

The contents tables of most address book containers and many folders do not support categorized sorting.

A contents table can be accessed by calling:

  • IMAPIContainer::GetContentsTable.

    – Or –

  • IMAPIProp::OpenProperty with PR_CONTAINER_CONTENTS or PR_FOLDER_ASSOCIATED_CONTENTS (folders only) specified as the property tag and IID_IMAPITable as the interface identifier.

Message store and address book providers must support both techniques for retrieving table properties. It is unacceptable for providers to support only one way for accessing these tables because clients expect to have the choice.

GetContentsTable accepts as input several flags that specify preferences. When set, the MAPI_ASSOCIATED flag retrieves an associated contents table. Because some folders do not support associated contents, and there is no way for clients to determine this ahead of time, GetContentsTable sometimes returns the error MAPI_E_NO_SUPPORT when an associated contents table is requested.

The MAPI_DEFERRED_ERRORS flag indicates to the implementer of the table that any errors encountered during the call do not need to be reported until some later time.

The call to IMAPIProp::OpenProperty involves accessing a contents table by opening its corresponding property, PR_CONTAINER_CONTENTS for address book contents tables and standard folder contents tables, and PR_FOLDER_ASSOCIATED_CONTENTS for associated contents tables. Although neither or these properties can be retrieved through a folder or container's IMAPIProp::GetProps method, they are included in the property tag array that is returned by the IMAPIProp::GetPropList method.

PR_CONTAINER_CONTENTS can also be used to include or exclude a contents table from a copy operation. If a client specifies PR_CONTAINER_CONTENTS in the lpExcludeProps parameter for IMAPIProp::CopyTo in a copy operation, the new folder or container will not support the contents table of the original folder or container.

Address book container and folder contents tables have a lengthy list of required columns — columns that clients can expect to be available after they retrieve the table from GetContentsTable or OpenProperty. Providers can add to this required set if necessary and clients, through the SetColumns method, can also request modifications.

The required columns for each of the types of contents tables are:

Required column | Type of contents table
PR_ADDRTYPE | Address book container tables
PR_DISPLAY_NAME | Address book container tables
PR_DISPLAY_CC | Message store folder tables
PR_DISPLAY_TO | All folder contents tables
PR_DISPLAY_TYPE | Address book container tables
PR_ENTRYID | All contents tables
PR_HASATTACH | All folder contents tables
PR_INSTANCE_KEY | All contents tables
PR_LAST_MODIFICATION_TIME | Message store folder tables
PR_MAPPING_SIGNATURE | Message store folder tables
PR_MESSAGE_CLASS | All folder contents tables
PR_MESSAGE_DOWNLOAD_TIME | Remote transport folder tables
PR_MESSAGE_FLAGS | All folder contents tables
PR_MESSAGE_SIZE | All folder contents tables
PR_MSG_STATUS | All folder contents tables
PR_OBJECT_TYPE | All contents tables
PR_PARENT_ENTRYID | Message store folder tables
PR_RECORD_KEY | Address book container and message store folder tables
PR_SENT_REPRESENTING_NAME | Remote transport folder tables
PR_STORE_ENTRYID | Message store folder tables
PR_STORE_RECORD_KEY | Message store folder tables

The entry identifier available with each row can either be a short- or long-term entry identifier, depending on the table implementation. Short-term entry identifiers are typically used in situations where performance is an issue. Either type of entry identifier can be used to access the corresponding object.

Contents tables also have a set of columns that are optional but commonly included by service providers in their implementations. These optional columns are:

Optional column | Type of contents table
PR_CLIENT_SUBMIT_TIME | Message store folder tables
PR_CONTENT_COUNT | Standard folder contents tables
PR_CONTENT_UNREAD | Standard folder contents tables
PR_CONVERSATION_INDEX | Message store folder tables
PR_CONVERSATION_KEY | Message store folder tables
PR_EMAIL_ADDRESS | Address book container tables
PR_IMPORTANCE | All folder contents tables
PR_MESSAGE_DELIVERY_TIME | All folder contents tables
PR_NORMALIZED_SUBJECT | All folder contents tables
PR_PRIORITY | All folder contents tables
PR_SEARCH_KEY | Address book container tables
PR_SEND_RICH_INFO_ | Address book container tables
PR_SENDER_NAME | All folder contents tables
PR_SENSITIVITY | All folder contents tables
PR_SUBJECT | All folder contents tables
PR_TRANSMITTABLE_DISPLAY_NAME | Address book container tables

Message store providers must also include PR_PARENT_DISPLAY for search-result folders contents tables only.

Named properties may be added to the column set of a folder contents table only if all messages in the folder have the same mapping signature, that is, the same mapping of property names to property identifiers. Folder contents tables should support adding message class specific properties to the column set, at least if they support the creation of arbitrary messages in the folder.

Clients can save the default sort order for a folder contents table by calling its IMAPIFolder::SaveContentsSort method. If the RECURSIVE_SORT flag is specified on the call, the sort order can be made to apply to all of the subfolders within the folder.


Display Tables

A display table describes how to show a specific type of dialog box — one having one or more tabbed property pages dedicated to displaying and possibly editing one or more properties. Associated with every display table is an IMAPIProp interface implementation. The IMAPIProp implementation maintains the property data that is presented in the dialog box.

The rows in a display table represent the controls, or user interface objects, that appear in the dialog box. MAPI defines many types of controls, some with static values and some with dynamic values that a user can change. Most controls can be associated with properties maintained with the IMAPIProp implementation. When a user changes the value of a modifiable control, the corresponding property is updated.

Service providers implement display tables and the IMAPIProp interface. Creating a display table is similar to writing a program with a scripting language. Service providers can create a display table by:

  • Calling the BuildDisplayTable function.

    – Or –

  • Including custom code that populates the display table directly using a table data object — an object that supports the ITableData interface.

The BuildDisplayTable function combines information from display table structures with visual elements from a dialog box resource to build display table rows. The function returns a pointer to an IMAPITable interface implementation, and, if requested, a pointer to an ITableData interface implementation.

Using BuildDisplayTable to create a display table is straightforward and makes maintenance easier when visual elements of the display change. However, service providers that prefer not to use BuildDisplayTable can create a display table with custom code that uses the methods of ITableData. For example, service providers that have an existing template structure for their property pages might want to create custom code rather than use BuildDisplayTable.

There are a variety of ways service providers can implement the property interface for their display table. These include:

  • Supplying a standard IMAPIProp implementation.
  • Supplying a wrapped IMAPIProp implementation that includes special processing before making the standard calls.
  • Supplying an IPropData implementation.

The type of implementation depends on the characteristics of the data to be displayed and the responsible service provider. For example, if there is an implicit relationship between the data in two edit controls and one of the controls changes, the IMAPIProp implementation must change the value of the other control appropriately.

Display tables have the following properties in their required column set:

PR_XPOS | PR_YPOS
PR_DELTAX | PR_DELTAY
PR_CONTROL_TYPE | PR_CONTROL_FLAGS
PR_CONTROL_STRUCTURE | PR_CONTROL_ID

PR_XPOS and PR_YPOS specify the X and Y coordinates of the upper left corner of the control. The horizontal units are 1/4 of the dialog base width unit; the vertical units are 1/8 of the dialog base height unit. Windows computes the current dialog base units from the height and width of the current system font. The coordinates are relative to the origin of the property page area. The size of property pages is limited to approximately 200 by 180 dialog units.

PR_DELTAX and PR_DELTAY are the width and height of the control. These are ULONG values. The width units are 1/4 of the dialog base width unit; the height units are 1/8 of the dialog base height unit. The coordinates are relative to the origin of the control.

The other four properties describe various characteristics of the control. PR_CONTROL_TYPE indicates the type of control. MAPI defines twelve types of controls, each with a different set of attributes. These attributes are described in the flags property, PR_CONTROL_FLAGS. Examples of attributes include whether or not a control is editable or required.

The control structure, PR_CONTROL_STRUCTURE, contains information relevant to the particular type of control. Each type of control is described with a different structure. For example, edit controls are described with the DTBLEDIT structure. DTBLEDIT structures contain members that list the number of and specific types of characters that can be placed on the control and a property tag that identifies the property whose value is to be displayed in the control. PR_CONTROL_STRUCTURE is stored as a binary property.

The control identifier, PR_CONTROL_ID, uniquely identifies the control in the dialog box described by the display table. PR_CONTROL_ID is set from the values placed in the lpbNotif and cbNotif members of the DTCTL structure that is used by BuildDisplayTable to create the display table. Because MAPI sometimes combines display tables, the identifier in PR_CONTROL_ID should always be unique. Typically, providers assign a GUID structure to PR_CONTROL_ID to ensure its uniqueness. The PR_CONTROL_ID property is included in the TABLE_NOTIFICATION structure when a display table notification is generated.

For more information about display tables, see Implementing a Display Table and About Display Table Notifications.


Hierarchy Tables

A hierarchy table contains information about the folders in a message store or the containers in an address book container. Each row of a hierarchy table contains a set of columns with information about one folder or address book container. Hierarchy tables are used primarily by clients and implemented by message store providers to show a tree of folders and subfolders and implemented by address book providers to show a tree of containers within the address book. Containers that cannot hold subcontainers, as indicated by the absence of the AB_SUBCONTAINERS flag in their PR_CONTAINER_FLAGS property, do not implement a hierarchy table.

A hierarchy table can be accessed by calling:

  • IMAPIContainer::GetHierarchyTable.

    – Or –

  • IMAPIProp::OpenProperty passing PR_CONTAINER_HIERARCHY as the property tag and IID_IMAPITable as the interface identifier.

Containers and folders must support both techniques for retrieving table properties. It is unacceptable for service providers to support only one way for accessing these tables because clients expect to have the choice.

The call to IMAPIProp::OpenProperty involves accessing the hierarchy table by opening its corresponding property, PR_CONTAINER_HIERARCHY. Although PR_CONTAINER_HIERARCHY cannot be retrieved through a folder or container's IMAPIProp::GetProps method, it is included in the property tag array that is returned by the IMAPIProp::GetPropList method.

PR_CONTAINER_HIERARCHY can also be used to include or exclude a hierarchy table from a copy operation. If a client specifies PR_CONTAINER_HIERARCHY in the lpExcludeProps parameter for IMAPIProp::CopyTo in a copy operation, the new folder or container will not support the hierarchy table of the original folder or container.

The following properties make up the required column set in a hierarchy table:

PR_COMMENT | PR_DEPTH
PR_DISPLAY_NAME | PR_DISPLAY_TYPE
PR_ENTRYID | PR_INSTANCE_KEY
PR_OBJECT_TYPE | PR_STATUS

PR_DISPLAY_NAME contains the name for the container or folder that should appear in the display of the hierarchy.

PR_ENTRYID is the entry identifier associated with this container or folder. It is expected to be a long-term entry identifier. Clients and MAPI can pass this entry identifier to OpenEntry to open the container or folder and view its contents by calling IMAPIContainer::GetContentsTable.

PR_DEPTH is a numeric value that indicates the level of indentation for this container or folder with zero being the top level. The deeper in the hierarchy a a container or folder resides, the higher the value for its PR_DEPTH property. Clients use the PR_DEPTH property to display a hierarchy table appropriately so that users can clearly see parent and child relationships. Container or folder depth is always relative to the container or folder implementing the hierarchy table.

PR_OBJECT_TYPE is always set to MAPI_ABCONT for address book hierarchy tables and MAPI_FOLDER for folder hierarchy tables.

PR_DISPLAY_TYPE is a numeric value that relates to how a container or folder is displayed in the hierarchy table. It is mainly used for display purposes, to differentiate visually between types of containers or folders. Many message store and address book providers use icons for the different display types. It is up to the provider to supply these icons; MAPI does not supply defaults.

MAPI defines many values for PR_DISPLAY_TYPE, some that are valid for folders and others that are used with the hierarchy tables of address book containers. Typically, a folder's PR_DISPLAY_TYPE is set to DT_FOLDER to indicate a default folder icon, DT_FOLDER_LINK to indicate an icon that represents a link to another folder, or DT_FOLDER_SPECIAL to indicate an icon that is application-specific. DT_FOLDER_LINK is used with search-results folders.

In addition to these required columns, address book hierarchy tables must include the PR_CONTAINER_FLAGS property. PR_CONTAINER_FLAGS indicates various attributes about a container in the hierarchy and is used to distinguish one container from another.

An optional property for address book hierarchy tables is the PR_AB_PROVIDER_ID property.

Message-store hierarchy tables include these properties in their required column set:

PR_FOLDER_TYPE

PR_SUBFOLDERS

PR_CONTENT_COUNT

PR_CONTENT_UNREAD

Address book providers must support the following IMAPITable methods in their hierarchy table implementations because they are required by the MAPI integrated address book:

QueryColumns | QueryPosition
SeekRow | SeekRowApprox
FindRow | Restrict
CreateBookmark | FreeBookmark
QueryRows |


Message Service Table

The message service table contains information about the message services in the current profile. There is one message service table for every MAPI session, implemented by MAPI and used by special purpose client applications that provide configuration support.

The message service table is a static table.

Clients access the message service table by calling the IMsgServiceAdmin::GetMsgServiceTable method.

The following properties make up the required column set in the message service table:

PR_DISPLAY_NAME | PR_INSTANCE_KEY
PR_RESOURCE_FLAGS | PR_SERVICE_DLL_NAME
PR_SERVICE_ENTRY_NAME | PR_SERVICE_NAME
PR_SERVICE_SUPPORT_FILES | PR_SERVICE_UID

PR_DISPLAY_NAME is the displayable name for the message service and the default sort key column.

PR_INSTANCE_KEY serves as the index column for the table, uniquely identifying a row.

PR_RESOURCE_FLAGS describes the message service's capabilities.

PR_SERVICE_DLL_NAME is the name of the DLL that contains the message service implementation.

PR_SERVICE_ENTRY_NAME is the name of the message service's entry point function that conforms to the MSGSERVICEENTRY prototype.

PR_SERVICE_NAME is a required entry in the [Services] section in MAPISVC.INF. The value for this property will never be changed or localized. PR_SERVICE_NAME can be used to programmatically identify the message service.

PR_SERVICE_SUPPORT_FILES is a list of files that must be installed with the message service.

PR_SERVICE_UID is a unique identifier for the message service.


Message Store Table

The message store table contains information about message store providers in the current profile. There is one message store table for every MAPI session, implemented by MAPI and used by clients. Clients can use this table, for example, to locate all instances of a particular provider or to locate a specific message store.

The message store table is dynamic. If the user of a client application edits the profile, changing the default message store, for example, the values of the PR_DEFAULT_STORE properties for the affected message stores are immediately updated.

Clients access the message store table by calling the IMAPISession::GetMsgStoresTable method.

The following properties make up the required column set in the message store table:

PR_DEFAULT_STORE | PR_DISPLAY_NAME
PR_ENTRYID | PR_INSTANCE_KEY
PR_MDB_PROVIDER | PR_OBJECT_TYPE
PR_PROVIDER_DISPLAY | PR_RECORD_KEY
PR_RESOURCE_FLAGS | PR_RESOURCE_TYPE


One-Off Tables

A one-off table contains information about the templates that an address book provider supports for creating new recipients. One-off tables are implemented by address book providers, individual address book containers, and by MAPI, and can be persistent or temporary.

Note Do not confuse the templates in one-off tables with template identifiers; while their purposes are similar, their code constructs are nothing alike. Templates are used to create recipients of a particular type while template identifiers are used to bind the data of one recipient belonging to a host provider with code to support another recipient belonging to a foreign provider.

Clients create new recipients:

  • To add to the recipient list of an outgoing message.
  • To add to one of the containers in the address book.

In both scenarios, an address book provider is asked to return a one-off table. Address book providers can implement either a single one-off table to be used in both situations or a unique one-off table for each situation.

When the recipient will be included with an outgoing message, MAPI calls the address book provider's IABLogon::GetOneOffTable method to retrieve its one-off table. The one-off table includes templates which allow a user to enter information resulting in the creation of a recipient with a valid address. MAPI registers for notifications on this table, keeping it open so that changes can be reflected to the user. MAPI releases the table only when its subsystem or address book status objects' IMAPIStatus::ValidateState method is called.

When the recipient will be added to a container, MAPI makes a different call, invoking the container's IMAPIProp::OpenProperty method to retrieve its PR_CREATE_TEMPLATES property. The set of templates included in this one-off table represents the types of recipients that can be added to the container. For example, mail servers often expose one container for every gateway that is installed so that each container only holds addresses specific to the corresponding gateway.

MAPI provides a one-off table that includes its own templates as well as templates from each of the address book providers in the session. MAPI provides a generic template that can be used to create a new recipient for any address type, assuming that the user knows its format. Address book providers use this one-off table by calling IMAPISupport::GetOneOffTable. Each of the templates included in the MAPI one-off table results in the creation of recipients with valid recipient addresses.

Address book providers typically supply one template for every address type they support. However, support for templates is not required. Address book providers that do not allow the creation of new addresses can return MAPI_E_NO_SUPPORT when MAPI calls to request a one-off table. Address book providers that do allow new address creation but do not supply any templates can call IMAPISupport::GetOneOffTable to use the templates listed in the MAPI one-off table.

The following properties make up the required column set in one-off tables:

PR_ADDRTYPE | PR_DEPTH
PR_DISPLAY_NAME | PR_DISPLAY_TYPE
PR_ENTRYID | PR_INSTANCE_KEY
PR_SELECTABLE |

PR_ADDRTYPE indicates the type of address that can be associated with the new recipient created with the template.

PR_DISPLAY_NAME and PR_DISPLAY_TYPE associate data with the new recipient. PR_DISPLAY_NAME contains a character string that identifies the new recipient and PR_DISPLAY_TYPE contains a constant that identifies the type of icon to be displayed with the row. Templates for messaging users have their PR_DISPLAY_TYPE column set to DT_MAILUSER; templates for distribution lists have their PR_DISPLAY_TYPE column set to DT_DISTLIST.

PR_ENTRYID is the entry identifier of the template to be used to create a new recipient. This entry identifier can be passed to future IAddrBook::NewEntry, IAddrBook::OpenEntry, and IABContainer::CreateEntry calls. Containers set the PR_ENTRYID column of their row for the default messaging user template to PR_DEF_CREATE_MAILUSER and the PR_ENTRYID column of their row for the default distribution list template to PR_DEF_CREATE_DL.

PR_DEPTH is used to support the hierarchical display of the entries in a one-off table by indicating the level of indentation for the template. Although one-off tables can be displayed either as a flat list or a hierarchical display, the latter is preferable and address book providers should support it by setting the PR_DEPTH column for each row appropriately. PR_DEPTH is zero-based; rows with a value of 0 in their PR_DEPTH column are not indented. The higher the value of PR_DEPTH, the more the row is indented. For example, rows with PR_DEPTH set to 1 are indented one tab while rows with PR_DEPTH set to 3 are indented three tabs.

PR_SELECTABLE is used to indicate whether or not a row in the table represents a template that can be selected and used to create a new recipient. Although most rows in a one-off table do represent templates, providers can include non-template rows. For example, a provider might want to organize the one-off table by template type, including a category row that appears in the display but is not used for recipient creation.

The following dialog box illustrates a one-off table with five rows, four of which represent templates and have their PR_SELECTABLE column set to TRUE. The one non-template row, indicated by the text "Special Address Types," has its PR_SELECTABLE column set to FALSE.


Outgoing Queue Tables

An outgoing queue table contains information about all the outgoing messages for a message store. Message store providers implement outgoing queue tables for the MAPI spooler to use. Stores that do not support the sending or receiving of messages need not implement this table.

To access an outgoing queue table, the MAPI spooler calls the IMsgStore::GetOutgoingQueue method.

There is a requirement that messages be preprocessed and submitted to the transport provider in the same order as they were sent by the client application. The MAPI spooler is designed to accept messages from the message store in ascending order of submission time. Because of this requirement, there can be some delay before some messages appear in the outgoing queue table.

Message stores should either allow sorting on the outgoing queue table so that the MAPI spooler can sort the messages by submission time, or the default sort order should be by ascending submission time.

The outgoing queue table must send notifications when the contents of the queue changes.

The following properties make up the required column set in outgoing queue tables:

PR_CLIENT_SUBMIT_TIME | PR_DISPLAY_BCC
PR_DISPLAY_CC | PR_DISPLAY_TO
PR_ENTRYID | PR_MESSAGE_FLAGS
PR_MESSAGE_SIZE | PR_PRIORITY
PR_SENDER_NAME | PR_SUBJECT
PR_SUBMIT_FLAGS |

For more information about how the outgoing queue table is used, see Sending Messages with Message Store Providers.


Profile Table

The profile table lists information about all profiles associated with a particular client application. There is one profile table for every session, implemented by MAPI for use by clients.

Clients access the profile table by calling the IProfAdmin::GetProfileTable method.

The profile table is a static table. Profiles that have been marked for deletion are not included in the profile table.

As with most table implementations, if GetProfileTable is called and there are no profiles available to the client, the table is created with zero rows.

The following properties make up the required column set in profile tables:

PR_DEFAULT_PROFILE

PR_DISPLAY_NAME


Provider Table

A provider table contains information about service providers. There are two different provider tables, both implemented by MAPI and used by clients. The first table, accessed by calling the IMsgServiceAdmin::GetProviderTable method, holds information about all of the providers for the current profile. The second table, accessed through IProviderAdmin::GetProviderTable, creates a table that stores information about all of the service providers for a message service.

These two tables have another difference. The provider table available through IMsgServiceAdmin::GetProviderTable contains only rows that represent service providers while the table available through IProviderAdmin::GetProviderTable may include rows that represent additional information associated with a service provider. This extra information is added to the profile with the "Sections" keyword of MAPISVC.INF. When a provider has extra profile sections, it stores the MAPIUIDs for these sections in the PR_SERVICE_EXTRA_UIDS property. PR_SERVICE_EXTRA_UIDS is saved in the message service profile section.

The following properties make up the required column set in both types of provider tables:

PR_INSTANCE_KEY | PR_DISPLAY_NAME
PR_PROVIDER_DISPLAY | PR_PROVIDER_DLL_NAME
PR_PROVIDER_ORDINAL | PR_PROVIDER_UID
PR_RESOURCE_FLAGS | PR_RESOURCE_TYPE
PR_SERVICE_NAME | PR_SERVICE_UID

The provider table can be used to display the current transport order or to change it. To display the current order, build a restriction to retrieve only those rows with the PR_RESOURCE_TYPE property set to MAPI_TRANSPORT_PROVIDER. Then use PR_PROVIDER_ORDINAL as a sort key to sort the table and retrieve all the rows with either the IMAPITable::QueryRows method or the HrQueryAllRows function.

To change the transport order, apply the same restriction and retrieve the rows. Then create an array of values from the PR_PROVIDER_UID property that represents the unique identifiers for the transport providers. When the identifiers are in the desired order, pass them to the IMsgServiceAdmin::MsgServiceTransportOrder method.

Once a provider table has been made accessible, it will not reflect subsequent changes, such as the addition or deletion of a provider.


Receive Folder Tables

A receive folder table contains information for all the folders designated as receive folders for a message store. A receive folder is a folder where incoming messages of a particular message class are placed. Message store providers implement receive folder tables and client applications use them by making a call to the IMsgStore::GetReceiveFolderTable method.

The following properties make up the required column set in receive folder tables:

PR_ENTRYID

PR_MESSAGE_CLASS

PR_RECORD_KEY


Recipient Tables

The recipient table contains information about all the recipients for a message. Message store providers implement recipient tables and client applications use them. Clients access a recipient table by making a call to the IMessage::GetRecipientTable method, or if the message store provider supports it, to the IMAPIProp::OpenProperty method. Clients access recipient tables with OpenProperty by specifying PR_MESSAGE_RECIPIENTS for the property tag and IID_IMAPITable for the interface identifier. Changes to a recipient table can be made by calling the IMessage::ModifyRecipients method.

Recipient tables have a different column set depending on whether the message has been submitted. The following properties make up the required column set in recipient tables:

PR_DISPLAY_NAME

PR_RECIPIENT_TYPE

PR_ROWID

The optional properties are:

PR_DISPLAY_TYPE

PR_ENTRYID

PR_SPOOLER_STATUS

PR_OBJECT_TYPE

Submitted messages should include these additional properties in their required column set:

PR_ADDRTYPE

PR_RESPONSIBILITY

Depending on a provider's implementation, additional columns, such as PR_SENDER_NAME and ENTRYID, might be in the table.

Any message store provider that supports message transmission — as indicated by the STORE_SUBMIT_OK bit being set in the provider's PR_STORE_SUPPORT_MASK property — should offer support for a particular set of restrictions in a recipient table implementation. The AND, OR, exist, and property restrictions are among the types of restrictions that should be available to recipient table users. Only the equal and not equal operators need to be supported on the property restriction. These restrictions must work with the following properties:

PR_ADDRTYPE

PR_EMAIL_ADDRESS

PR_RECIPIENT_TYPE

PR_RESPONSIBILITY

PR_SPOOLER_STATUS

PR_TRANSPORT_STATUS


Status Table

The status table contains information relating to the state of the current session. There is one status table for every MAPI session that includes information provided by MAPI and by service providers. MAPI provides data for three rows: a row for the MAPI subsystem, a row for the MAPI spooler, and a row for the integrated address book. Because transport providers are required to supply status information to the status table, there is one row for every active transport provider. Address book and message store providers can choose whether or not to support the status table.

Because each row is provided by a different resource, the set of columns can vary from row to row. There is a set of columns that every status object is required to supply and a set of columns that MAPI supplies. A service provider can add to these sets to expose provider-specific properties. For example, message store providers might add PR_STORE_RECORD_KEY to supply clients with the identifier of their message store. Clients must have advance knowledge of the existence of this extra information to be able to use it.

The following table lists the properties that must be in every status table row. The implementer of the status object provides some of the properties; others are computed by MAPI.

Properties provided by status object | Properties provided by MAPI
PR_DISPLAY_NAME | PR_PROVIDER_DLL_NAME
PR_STATUS_CODE | PR_RESOURCE_FLAGS
PR_RESOURCE_METHODS | PR_RESOURCE_TYPE

If the status object provides an identity, it should set PR_IDENTITY_DISPLAY, PR_IDENTITY_ENTRYID, and PR_IDENTITY_SEARCH_KEY, and include these properties in the table.

Four properties are computed by MAPI for each status table row:

PR_ENTRYID | PR_INSTANCE_KEY
PR_OBJECT_TYPE | PR_ROWID

MAPI assigns an entry identifier to the status row to enable clients to open the corresponding status object. A row identifier is also assigned to identify the row in the table as is an instance key to identify the data in the status object. The PR_OBJECT_TYPE property is set to MAPI_STATUS.

To access the status table, clients call the IMAPISession::GetStatusTable method. This call should not be made immediately upon startup. This is because GetStatusTable has to wait for the MAPI spooler to initialize the transport providers, an operation that is postponed until after the client has finished its logon. GetStatusTable is a relatively fast call after the MAPI spooler has completed its startup processing.

Status table information can be used in a variety of ways, such as to access a status object, to determine whether a client is running in a connected or offline mode, and to monitor a provider's state. For example, clients can open a specific service provider's status object by passing the value of the PR_ENTRYID property to the IMAPISession::OpenEntry method. The status object supports the IMAPIStatus interface, an interface that contains methods to change a service provider password, flush the message queue, display a configuration property sheet, or confirm status with a provider directly. Status table information can also be used to build a dialog box to inform clients of progress during a lengthy operation.

Service providers who do support the status table use the IMAPISupport::ModifyStatusRow method to create and update their row. Whenever a change occurs to their row, all advise sink objects registered to receive status table notifications must be notified. Service providers can call the IMAPISupport::Notify method if they are using the MAPI notification utility or call each advise sink's IMAPIAdviseSink::OnNotify method directly.


Tips for Working with Tables

Working with a MAPI table is a little like working with a relational database table. A user can limit the number of rows and columns in the view and specify their order. Rows can be retrieved one at a time or in groups. A cursor that keeps track of the current position can be moved to a specific place in the table.

To work with tables, clients use the read-only interface, IMAPITable : IUnknown, whereas service providers, depending on whether they own the data that the table is based on, can use either IMAPITable or ITableData : IUnknown. The operations defined in these interfaces can be categorized as operations that all users of tables either do or can invoke and operations that are not as widely used because they are more advanced. Some of the advanced operations are more complex to implement; others are no more complex, but are of interest to a small minority of MAPI components.

The more common operations are:

  • Column operations, which affect single columns. These include specifying the properties to be included in the column set and the order in which they should be included.
  • Row operations, which affect single rows.These include data retrieval and the maintenance operations: adding, deleting, and modifying a single row or rows.
  • Global operations, which affect the entire table. These include event notification, searching and sorting.


Retrieving Data from Table Rows

Retrieving rows from a table involves:

  • Obtaining the property values for all the columns.
  • Modifying the current position.

One of the required columns in most tables is an entry identifier — or PR_ENTRYID property — that can be used to open the object that represents the row. This entry identifier is usually a short-term entry identifier, one that does not persist past the lifetime of the table. However, it can be a long-term identifier if the service provider implementing the table only supports one type of entry identifier.

Clients and service providers can make one of the following calls to retrieve rows:

IMAPITable::QueryRows | Retrieves a specified number of rows starting with the current row in either a forward or backward direction.
HrQueryAllRows | Retrieves all of the rows in a table.
ITableData::HrQueryRow | Retrieves a row in a table according to the value of its index column. PR_INSTANCE_KEY is usually the index column for a table.

When an optional property is included as one of the columns in a table, some of the rows might have valid values for the column while others might not. Whether or not a valid value exists for a column depends on whether or not the object providing the information for the row sets the property. Depending on the implementation of the object, a non-existent property can be represented in the table as PR_NULL or an arbitrary value. Users of tables must be careful to differentiate between properties that are nonexistent and have meaningless values and properties that do exist and have valid values.


Table Positioning

The current position within a table is always indicated by a cursor. There is one cursor for each view of a table; its value is set by the table's implementer. When a client or service provider using the table makes a call to change the position of the table, the value of the cursor is reset. A table's position can be changed with:

  • A bookmark.
  • A fractional value.
  • A filter.


Setting a Table Position with a Bookmark

A bookmark is a resource that indicates a particular location in a table. Setting a bookmark makes it possible to return to a position at a later time, a feature that can significantly improve the performance of table operations. MAPI defines three standard bookmarks:

BOOKMARK_CURRENT | Points to the present row in a table.
BOOKMARK_BEGINNING | Points to the first row in a table.
BOOKMARK_END | Points to the last row in a table.

Table implementers are required to support these standard bookmarks and can also support others. However, because bookmarks are resources and resources are limited, bookmark users should free them as soon as possible.

To set a bookmark at the current table position
  • Call IMAPITable::CreateBookmark.

    Occasionally there will be insufficient memory available to allocate the new bookmark, causing CreateBookmark to return the MAPI_E_UNABLE_TO_COMPLETE error value.

To free a bookmark
  • Call IMAPITable::FreeBookmark.
To move the cursor to a bookmarked position
  • Call IMAPITable::SeekRow.

    SeekRow establishes a new value for the BOOKMARK_CURRENT position. SeekRow can be used, for example, to position a table ten rows from the current position or to start over at the beginning. Clients or service providers can seek to the current, beginning, or end of a table, or any other position that is associated with a predefined bookmark. They can move in either a forward or backward direction and limit the operation to a specified number of rows. As a rule, callers should seek through no more than 50 rows with SeekRow; IMAPITable::SeekRowApprox should be used with larger numbers of rows.


Setting Table Position with a Fractional Value

Table users can move to a position that represents an approximate percentage of rows in relation to the total. Rather than moving to an exact row, this method of positioning divides the table into portions based on fractions. Table users can move, for example, to a table's half-way point or to the row that is 7/8 of the way through the table.

To move the cursor an approximate number of rows
  • Call IMAPITable::SeekRowApprox.

    SeekRowApprox moves to the row that represents a particular percentage of rows in relation to the beginning of the table. This percentage is specified in the ulNumerator and ulDenominator parameters. SeekRowApprox is used frequently to implement scroll bars.

To determine a table's approximate position
  • Call IMAPITable::QueryPosition.

    QueryPosition can be used to inform the user of the current position. It sets a fractional value based on the number of rows in the table and the number of the current row. Expect that this value represents an approximation. Table implementers are encouraged not to calculate the exact position because accurate implementations can be expensive to invoke, especially on categorized tables.


Setting a Table Position with a Filter

Table users can move the cursor to a row that matches a set of criteria. Filters can be based on a variety of guidelines such as column property values, bitmasks, or subobjects. Filters are specified in MAPI using an SRestriction structure.

To position a table to the first row that matches the criteria established in a restriction
  • Call the FindRow method.

    Starting with the row represented by a particular bookmark, FindRow searches in either a forward or backward direction to locate a row that matches the criteria specified in the restriction. FindRow can be useful for implementing a scroll bar that is based on character strings, rather than fractional values. For example, a client can call MAPI's implementation of FindRow when searching through the integrated address book to enable a user, by entering one or more characters, to locate the first name that begins with the specified characters.


Tables and Memory Usage

An important issue connected with retrieving data from a table is memory usage. Lack of available memory can cause IMAPITable::QueryRows and HrQueryAllRows to fail, returning less than the desired number of rows. Deciding which method or function to use to retrieve table data depends on whether or not the table can be expected to fit in memory, and if it cannot, if failure is acceptable.

Since it is not always easy to determine the amount of data that will fit into memory at one time, MAPI provides some basic guidelines for a client application or service provider to follow. Remember that there are always exceptions, based on the particular table implementation and how the underlying data is stored.

The following guidelines can be used to evaluate table memory usage:

  • Clients that can tolerate occasional working set memory usage in the megabyte range and are written for 32-bit platforms can assume they will have no problems reading an entire table into memory. Clients written to run on 16-bit platforms should be more conservative.
  • Restrictions have an affect on a table's usage of memory. A severely restricted table with an extensive number of rows, such as a contents table, can be expected to fit into memory while an unrestricted large table usually cannot. However, large unrestricted tables might fit in memory if the table user has some extended knowledge about the table or control over its data.
  • Several of the tables owned by MAPI such as the status, profile, message service, provider, and message store tables, will usually fit in memory. These are generally small tables. However, there are exceptions. For example, a server-based profile provider might generate a larger profile table that will not be able to fit.

To retrieve all of the rows from a table that will fit into memory with no problems, call HrQueryAllRows, setting the maximum number of rows to zero.

To retrieve all of the rows from a table that might or might not fit into memory, generating an error, call HrQueryAllRows specifying a maximum number of rows. The maximum number of rows should be set to a number greater than the minimum number of rows that are needed. That is, if a client must access at least 50 rows from a 300 row table, the maximum number of rows should be set to at least 51.

To retrieve all of the rows from a table that is not expected to fit into memory, call QueryRows in a loop with a relatively small row count, as the following code sample illustrates:

HRESULT     hr;
LPSRowSet   pRows = NULL;
LONG        irow;
LONG            cAsk = 50;                  // adjust this value

while ((hr = pTable->QueryRows(cAsk, 0, &pRows)) == hrSuccess
        && pRows->cRows != 0)
{
    for (irow = 0; irow < prows->cRows; ++irow)
    {
        // process the row...
    }
    FreeProws(pRows);
    pRows = NULL;
}
if (hr)
{
    // handle the error...
}

When this loop completes and all the rows in the table have been processed and cRows is zero, the position of the cursor will usually be at the bottom of the table.


Working with Large Columns

Columns with string or binary property data can be large, possibly many thousands of bytes long. Because including one or more columns with hundreds of bytes in a view is often impractical, MAPI enables table implementers to truncate the value, most often to 255 bytes and less often to 510 bytes. Whenever possible, table implementers should include the full value of a property in a table column. The recommended alternative is to include only the first 255 bytes.

Clients cannot know in advance whether or not a table they are using truncates large columns. They should assume that a column represents a truncated property if the length of the column is either 255 or 510 bytes. If necessary, clients can directly retrieve the full value of a truncated column from the object by calling the object's IMAPIProp::GetProps method.

Clients building restrictions with large properties should be aware that it is up to the table implementer as to how these restrictions operate. Some table implementers allow restrictions that are built with a truncated column to be based on the truncated size while others base it on the entire value.


Working with Multivalued Columns

A multivalued column contains the data of a multivalued property, or property that has an array of values of the base type rather than a single value. Because none of the tables include multivalued properties in their default column sets, multivalued properties are included in a table only if the user of the table requests it.

Multivalued columns can be displayed in tables:

  • In a single row, with all of the property values appearing in the single column instance. This is the default.

    – Or –

  • In a series of rows, with one row for each of the property values. Each unique value appears in the column in its own row with there being as many rows as there are values in the multivalued property. Each row has a unique value for the PR_INSTANCE_KEY property, but the same values for the other columns.

    If a row contains more than one column with multiple values, for example, two columns with M and N values respectively, then M*N instances of the row appear in the table.

A table user requests the nondefault type of display by calling the IMAPITable::SetColumns method with the MVI_FLAG flag set in the property type of the multivalued column. The MVI_FLAG flag is a constant defined as the result of combining the MV_FLAG and MV_INSTANCE flags with a logical OR operation. In addition to being used in SetColumns, MVI_FLAG can also be passed to IMAPITable::SortTable in the lpSortCriteria parameter and IMAPITable::Restrict in the ulPropTag member of the lpRestriction parameter. When passed the MVI_FLAG, SortTable performs similarly to SetColumns, adding one row for each value in the multivalued column and sorting on the single values in the instances. One row is added for each value.

Restrict, however, does not expand the multivalued column into additional computed rows. A multivalued column with the MVI_FLAG set instructs the service provider to use that column in restricting the table. If there is a property value in the restriction, it must be a single value property tag identical to the one that would be returned by IMAPITable::QueryRows for the column.

Table implementers are only required to support the default type of display and can return the MAPI_E_TOO_COMPLEX value when a caller requests the other alternative. The ability to support both types of display is most important for message store providers implementing folder contents tables.


Working with Unicode Columns

Character strings in tables can be represented using standard 8-bit characters, which are property type PT_STRING8, or 16-bit Unicode characters, which are property type PT_UNICODE. Table implementers are free to choose whether or not their tables support Unicode strings. Because Unicode adds value for both clients and service providers by extending the feature set, supporting Unicode wherever possible is recommended. However, most of the table implementations supplied by MAPI do not currently support Unicode.

Many table methods accept a flag that dictates whether or not string property values are expected to be Unicode. On input, specifying the MAPI_UNICODE flag indicates to the table implementer that all string property values passed in with the call are Unicode strings and have property types of PT_UNICODE. On output, this flag indicates that all returned string property values should be Unicode strings, if possible. Whether the flag has a meaning for input or output depends on the method. Table implementers that do not support Unicode and are passed the MAPI_UNICODE flag return the MAPI_E_BAD_CHAR_WIDTH value.


Determining a Table's End

A common error is to assume that the end of the table has been reached when:

  • QueryRows has been called in a loop, with the end of the loop determined by the row count returned by IMAPITable::GetRowCount.

    The count that GetRowCount returns does not always represent the exact number of rows in the table; it is an approximate count.

  • QueryRows has been called with a fixed number of rows and less rows are returned.

    It is not until QueryRows returns a row set with a row count equal to zero that there are no more rows to retrieve.

Note The only time that a caller can assume that the cursor is positioned at the end of the table for a positive row count or at the beginning of the table for a negative row count is when the value S_OK and zero rows are returned. The value MAPI_E_NOT_FOUND is never returned.


Sorting and Categorization

Sorting a table places rows in an order that makes sense for its viewer. For example, one viewer might prefer to see the contents table of a folder sorted by message subject so that all the threads of a conversation are together while another viewer might want the messages sorted by the name of the sender. A newly instantiated table is not necessarily sorted in any particular order.

There are two types of sorting:

  • Standard sorting
  • Categorized sorting

With standard sorting, all of the rows are displayed in a flat list using one or more columns as a sort key. With categorized sorting, the rows are displayed hierarchically with one or more columns as the sort key. Within each category, there is a special heading row that contains the following columns:

  • The column or columns that make up the sort key
  • PR_CONTENT_UNREAD
  • PR_INSTANCE_KEY
  • PR_DEPTH
  • PR_ROW_TYPE.

Indented under the heading row are all the rows from the table that contain columns with values that match the sort key. These rows are called the leaf rows. Leaf rows contain all the columns in the column set minus the sort key columns.

The contents tables of folders often support categorized sorting in addition to standard sorting. The contents tables of address book containers typically support only standard sorting.

A category can have two states: collapsed and expanded. When a category is in the collapsed state, only the heading row is returned from IMAPITable::QueryRows. When a category is in the expanded state, all of the rows related to the category are returned. This includes the heading row and the leaf rows.

Each category in a table view can be expanded or collapsed independently. That is, not all categories must be in the same state at the same time; some categories can be collapsed while others are expanded.

The user of a categorized table decides how it is displayed. One common option is to use a control provided in the Platform SDK called the treeview control. Treeview controls are list boxes that support information in a tree-like structure. Heading rows for categories in the expanded state are marked with a minus sign while heading rows for categories in the collapsed state are marked with a plus sign. Expanded categories are displayed with the leaf rows indented under the heading rows.

The following illustration shows a categorized contents table with an expanded category to illustrate the difference between how an expanded and collapsed category can appear to the user. The table is sorted by sender name — the PR_SENDER_NAME property. Heading rows contain the sender name and the computed properties for the row. The category where sender name is equal to Bill Lee is expanded to include five leaf rows. All of the leaf rows are visible and there is a minus sign next to the heading row, indicating that no further expansion of the category is possible.

In the following illustration, the category is collapsed with none of the leaf rows included in the display. The heading row has a plus sign indicating that the category can be expanded further.

To collapse and expand a category, a client application or service provider uses the following IMAPITable methods:

GetCollapseState

SetCollapseState

ExpandRow

CollapseRow


About Restrictions

A restriction is a way to limit the number of rows in a view to only those rows with values for columns that match specific criteria. There are many different opportunities for using restrictions with tables. Client applications can use restrictions, for example, to filter a contents table for messages sent by a particular person, to search for rows that either do not support a property or have set a property to a specific value, or to look for duplicate recipients within a message.

The IMAPITable::Restrict and IMAPITable::FindRow methods are used to set restrictions on a table. Restrict applies the restriction to the table without retrieving any rows. To retrieve only those rows that meet the restriction, a subsequent call to IMAPITable::QueryRows or a similar method is required. FindRow applies the restriction and retrieves the first row in the table that matches the criteria. FindRow applies a temporary restriction, in existence only for the duration of the call, whereas Restrict applies a more permanent restriction.

Some clients can build a restriction using columns that are not in the current column set. Supporting such a restriction is optional and table implementers that do support it add value, particularly for contents tables. Table implementers that do not support it can return the MAPI_E_TOO_COMPLEX value from a Restrict call or the MAPI_E_NOT_FOUND value from a FindRow call.

Clients should be aware that, even if the provider does support restrictions on columns not in the current column set, they will get better performance overall by specifying the columns they intend to use in their restrictions with SetColumns.


Types of Restrictions

There are many types of restrictions, some that focus on specific columns. All table implementations are expected to support restrictions on the columns in the current column set. However, to add value, table implementers can also support restrictions based on object properties that are not currently in the table view.

Some restrictions can be combined using a restriction that performs a logical AND, OR, or NOT operation. For example, most property restrictions must be joined with exist restrictions using AND restrictions. There are a few exceptions, such as when the property used in the property restriction is the PR_ANR property or when it is a required column in a table. A client building restrictions to limit its view should use exist restrictions with its property restrictions because MAPI does not specify how service providers should evaluate property restrictions when a property does not exist. It is reasonable and recommended that service providers fail the restriction, but there are no requirements.

A restriction is defined using the SRestriction data structure which contains a union of more specialized restriction structures and an indicator of the type of structure included in the union.

Each of the specialized restriction structures in the union represents a different type of restriction. The types of restrictions and their associated data structures are:

Type of restriction | Associated data structure | Description
Compare property | SComparePropsRestriction | Compares two properties of the same type.
AND | SAndRestriction | Performs a logical AND operation on two or more restrictions.
OR | SOrRestriction | Performs a logical OR operation on two or more restrictions.
NOT | SNotRestriction | Performs a logical NOT operation on two or more restrictions.
Content | SContentRestriction | Locates specified data.
Property | SPropertyRestriction | Specifies a particular property value as criteria for matching. Can be used, for example, to search for a particular type of attachment.
Bitmask | SBitMaskRestriction | Applies a bitmask to a PT_LONG property, typically to determine if particular flags are set.
Size | SSizeRestriction | Tests the size of a property using standard relational operators.
Exist | SExistRestriction | Tests whether or not an object has a value for a property.
Subobject | SSubRestriction | Used for searching through subobjects, or objects that cannot be accessed with an entry identifier (recipients and attachments). Can be used, for example, to look for messages for a particular recipient.
Comment | SCommentRestriction | Associates an object with a set of named properties.

Some restrictions use regular expressions, and MAPI supports a limited form of regular expression notation in the style that is used in the grep utility. For a discussion of MAPI's use of regular expressions, see Regular Expressions.

The comment restriction is used by clients that save restrictions on disk to keep application-specific information with the restriction. For example, a client saving the name of a named property used in a property restriction can do so with a comment restriction. Saving the name is not possible in a property restriction; the SPropertyRestriction data structure holds only the property tag. Comment restrictions are ignored by Restrict in that they have no effect on the rows returned by QueryRows after a Restrict call has been made.


Address Book Restrictions

Address book providers are required to support three types of restrictions on the contents tables of their containers:

  • Ambiguous name property restrictions
  • Instance key property restrictions
  • Prefixed display name content restrictions

Ambiguous name restrictions are property restrictions using the PR_ANR property to match recipient names with entries in address book containers. The PR_ANR property restriction is a "best guess" type of search whereby address book providers can choose the matching property that works best for their container. For example, one address book provider might implement the PR_ANR restriction by matching recipient names against the PR_ACCOUNT property of each container entry whereas another provider might use PR_DISPLAY_NAME.

MAPI recommends that implementations of the PR_ANR restriction strike a balance between adequate performance and user satisfaction. User satisfaction can be compromised when an address book provider implements the restriction in such a way that too few or too many matches are found. Some address book providers support what is known as a distinguished, or common, name that is not displayable in a dialog box but can match an ambiguous name restriction.

A typical implementation might be to parse the recipient's display name into words, matching any entry that contains all of the words. Attention to details such as sensitivity to word position, whether or not nonconsecutive words are matched, and the choice of separator characters can vary. For example, if the name to be resolved is "Bill L," a typical PR_ANR restriction would select the following entries as matching:

Billy Larson

Bill Lee

Bill Logan Jr.

Sam Bill Lee

Instance key restrictions, or PR_INSTANCE_KEY property restrictions, are used in the implementation of list boxes that are used in client applications for viewing MAPI tables. Some list box implementations allow users to make multiple selections, scroll up or down, and return to the first item selected. To implement this behavior, clients call IMAPITable::FindRow, passing a property restriction on the PR_INSTANCE_KEY property to the method. Address book providers are required to support this restriction.

Another feature of list boxes used for table viewing is the ability to position the cursor based on a set of prefix characters. As the user starts typing prefix characters, the client moves the cursor to the first item that begins with these characters. Clients implement this feature with a content restriction based on the PR_DISPLAY_NAME property and the FL_PREFIX fuzzy level.


Building a Restriction

To build a restriction, a client application creates a hierarchy of one or more restriction structures of various types and passes a pointer to the hierarchy to the IMAPITable::Restrict or IMAPITable::FindRow method. The illustration that follows and the code sample in Sample Restriction Code demonstrate how a typical restriction is implemented with linked restriction structures of different types. In this example, a user of a client application is trying to find all messages that contain the word "volleyball" in the subject line and were sent to Sue from Sam. First, a generic SRestriction structure is allocated. This structure becomes the basis for other calls to the MAPIAllocateMore function to create linked SRestriction and SPropValue structures that can be freed with a single call to MAPIFreeBuffer. Because the criteria to apply to the set of messages is in three parts, the top level restriction structure is an AND restriction. The SAndRestriction structure's cRes member is set to 3 to indicate the three restrictions to evaluate and its lpRes member is set to a three member array of SRestriction structures.

To search for messages that are sent to a particular recipient, it is necessary to search the recipient table for each message rather than the message itself. A subobject restriction is used to perform the recipient table search. Therefore, the first member of the array points to an SSubRestriction structure with its ulSubObject member set to PR_MESSAGE_RECIPIENTS. Then, to specify what to look for in the recipient table, a content restriction is used.

The second and third members of the array are more straightforward. They both point to content restriction structures, one to search for messages that have a PR_SENDER_NAME property set to "Sam" and another that has a PR_SUBJECT property set to "volleyball."


Sample Restriction Code

The following sample code shows how to create a restriction that filters out all messages that do not contain the word "volleyball" in the subject line and were not sent to Sue from Sam. A tree of SRestriction structures is required, with the top node being an AND restriction implemented with an SAndRestriction structure. The three restrictions that are joined by the AND operation are a subobject restriction that searches for messages sent to Sue, a content restriction that searches for messages from Sam, and another AND restriction that searches for messages that have a subject containing "volleyball." Because PR_SUBJECT is not a required property, an exist restriction must be included.

This code uses dynamic allocation and initialization; it is possible to allocate and initialize statically as well. In the interest of brevity, the error checking that must occur following the allocation calls is not included in the sample.

HRESULT BuildRestriction (LPTSTR pszSent, LPTSTR pszFrom,
                                LPTSTR pszSubjectText);
{
    LPSRestriction pRest, pAndRes, pObjRes, pSubjAndRes;
    LPSPropValue pRecip, pSender, pSubject;
    HRESULT hResult;
    ULONG ulResCount = 3, ulSubjCount = 2

    // Allocate and build AND restriction to join criteria
    hResult = MAPIAllocateMore (sizeof(SRestriction)*ulResCount, pRest,
            (LPVOID *)&pAndRes);
    pRest->rt = RES_AND;
    pRest->res.resAnd.cRes = ulResCount;
    pRest->res.resAnd.lpRes = pAndRes;

    // Allocate and build subobject restriction to search recipient list
    hResult = MAPIAllocateMore (sizeof(SRestriction), pRest,
            (LPVOID *)&pObjRes);
    pAndRes[0].rt = RES_SUBRESTRICTION;
    pAndRes[0].res.resSub.ulSubObject = PR_MESSAGE_RECIPIENTS;
    pAndRes[0].res.resSub.lpRes = pObjRes;

    // Allocate and build content restriction to look for recipient
    hResult = MAPIAllocateMore (sizeof(SPropValue), pRest,
            (LPVOID *)&pRecip);
    pObjRes->rt = RES_CONTENT;
    pObjRes->res.resContent.ulFuzzyLevel =
            FL_FULLSTRING | FL_IGNORECASE;
    pObjRes->res.resContent.ulPropTag = pRecip->ulPropTag =
            PR_DISPLAY_NAME;
    pObjRes->res.resContent.lpProp = pRecip;
    pRecip->Value.LPSZ = pszSent;              // pszSent set to Sue

    // Allocate and build content restriction to look for sender
    hResult = MAPIAllocateMore (sizeof(SPropValue), pRest,
            (LPVOID *)&pSend);
    pAndRes[1].rt = RES_CONTENT;
    pAndRes[1].res.resContent.ulFuzzyLevel =
            FL_FULLSTRING | FL_IGNORECASE;
    pAndRes[1].res.resContent.ulPropTag = pSend->ulPropTag =
            PR_SENDER_NAME;
    pAndRes[1].res.resContent.lpProp = pSend;
    pSend->Value.LPSZ = pszName;                    // pszName set to Sam

    // Allocate and build AND restriction to look for subject
    hResult = MAPIAllocateMore (sizeof(SRestriction)*ulSubjCount, pRest,
            (LPVOID *)&pSubjAndRes);
    pRest->rt = RES_AND;
    pRest->res.resAnd.cRes = ulResCount;
    pRest->res.resAnd.lpRes = pAndRes;

    // Create an AND restriction to search for subject
    hResult = MAPIAllocateMore (sizeof(SPropValue), pRest,
            (LPVOID *)&pSubjAndRes);
    pAndRes[2].rt = RES_AND;
    pAndRes[2].res.resAnd.cRes = ulSubjCount;
    pAndRes[2].res.resAnd.lpRes = pSubjAndRes;

    // Exist restriction to check that PR_SUBJECT exists
    hResult = MAPIAllocateMore (sizeof(SPropValue), pRest,
            (LPVOID *)&pSubj);
    pSubjAndRes[0].rt = RES_EXIST;
    pSubjAndRes[0].res.resExist.ulReserved1 = 0;
    pSubjAndRes[0].res.resExist.ulReserved2 = 0;
    pSubjAndRes[0].res.resExist.ulPropTag = PR_SUBJECT;

    // Content restriction to check for "volleyball" in subject
    hResult = MAPIAllocateMore (sizeof(SPropValue), pRest,
            (LPVOID *)&pSubj);
    pSubjAndRes[1].res.resContent.ulFuzzyLevel =
            FL_SUBSTRING | FL_IGNORECASE;
    pSubjAndRes[1].res.resContent.ulPropTag = pSubj->ulPropTag =
            PR_SUBJECT;
    pSubjAndRes[1].res.resContent.lpProp = pSubj;
    pSubj->Value.LPSZ = pszSubjectText;

    return hResult;
}


About Table Notifications

Clients often rely on table notifications to learn of changes to objects rather than registering to receive notifications directly from the objects. Typical changes that cause notifications to be sent include the addition, deletion, or modification of a row and any critical error. When notifications arrive, clients can determine whether or not to make another call to reload the table.

Because table notifications are asynchronous, there are a few issues that can make handling notifications less than straightforward:

  • The data passed in the TABLE_NOTIFICATION structure might not represent the table's most current state.

    For example, a client might make a change to a message and then decide to delete it. The message store provider implementing the contents table that included the message sends two notifications: a TABLE_ROW_MODIFIED event followed by a TABLE_ROW_DELETED event. Depending on how the message store provider times notifications, the client might receive the TABLE_ROW_MODIFIED notification after the deletion of the row.

  • The column set included with a notification might be different from the table's current column set.

    MAPI requires that the notification column set match the column set that was in effect at the time that the notification was generated. Because it is possible for a client to call IMAPITable::SetColumns to alter the column set at any time — including after a notification — the two column sets may not be synchronized.

  • Table notifications are only sent for rows that are part of the view.

    That is, if a row is excluded from the view due to a restriction or because the table is in a collapsed state, no notification will be sent if that row changes. Also, no notifications are sent to inform a client about a change in category state.

Clients should be aware that not all tables support the TABLE_SORT_DONE notification and should be prepared to handle this condition by:

  1. Forcing the sort to be synchronous.
  2. Reloading the rows of the table when IMAPITable::SortTable returns.


About Display Table Notifications

Notifications on a display table are sent by the service provider responsible for creating the display table to MAPI. MAPI registers for these notifications by calling a display table's IMAPITable::Advise method and specifying the table modified event.

As with all table notifications, display table notifications include a TABLE_NOTIFICATION structure. Only the ulTableEvent and the propIndex members of this structure are significant; the other members are ignored. The ulTableEvent member is set to TABLE_ROW_MODIFIED and the propIndex member is set to the value of the PR_CONTROL_ID column in the corresponding row. MAPI responds to the notification by calling the IMAPIProp::GetProps method for the property displayed in the control and by displaying the new value.

Display table notifications can be used by a service provider to coordinate changes to related controls on the dialog box. For example, if the property interface implementation needs to refresh one or more fields on the dialog box — perhaps in response to another control that has set the DT_SET_IMMEDIATE flag in its PR_CONTROL_FLAGS property — it can generate a display table notification. A display table notification can alert the property interface implementation that the value of one or more controls needs to be reread due to a change being made or an external event occurring.

A service provider can issue display table notifications by:

  • Calling ITableData::HrNotify, if the display table was built with a table data object.

    – Or –

  • Using its own code, if the display table was built with the provider's IMAPITable implementation.

MAPI responds to display table notifications when necessary by rereading a control's value from the property interface implementation. The following table describes the details surrounding how MAPI handles notifications for specific types of controls.

Control | MAPI action
Button Calls IMAPIProp::OpenProperty to retrieve the control object by way of the property represented by the ulPRControl member of the DTBLBUTTON structure if the call had failed previously.
Calls the control object's IMAPIControl::GetState to determine whether the button should be enabled and enables or disables the button accordingly.
Check box | Rereads the value for the ulPRPropertyName member.
Combo box Reopens the table associated with the ulPRTableName member of the DTBLCOMBOBOX structure.
Rereads all of the rows including the value for the ulPRPropertyName member.
Drop-down list box Reopens the table associated with the ulPRTableName member of the DTBLDDLBX structure and rereads all of the rows.
Calls IMAPIProp::GetProps to retrieve the values for the properties stored in the ulPRDisplayProperty and the ulPRSetProperty members.
Edit | Rereads the property and redisplays.
Group box | Ignores the notification.
Label | Ignores the notification.
Multiple selection list box | If one of the columns is an entry identifier, refreshes the list box. The corresponding object is not closed or reloaded.
Single selection list box | Reads the set property, trying to identify it.
Multivalued list box | Rereads the property and repopulates the list box.
Tabbed page | There are no notifications for this control; everything is static.
Radio button | Rereads the property that is associated with the button and is stored in the ulPropTag member of the DTBLRADIOBUTTON structure and makes the appropriate selection with the controls.

›


About Asynchronous Table Operations

The IMAPITable interface includes three methods that operate asynchronously and three methods for controlling an asynchronous operation. The following table lists these methods:

Asynchronous operation | Asynchronous control method
SetColumns | GetStatus
Restrict | Abort
SortTable | WaitForCompletion

To retrieve status information about a table's type and current operation
  • Call IMAPITable::GetStatus.

    With GetStatus, a table user can determine if the table is static or dynamic, if an operation is in progress or has completed, and if an error has occurred from a completed operation. For example, if a client needs to cancel a sort operation because it is taking too much time, the client can first call GetStatus to determine if, in fact, a sort operation is presently processing. Then the client can call IMAPITable::Abort to stop it.

To suspend activity until an asynchronous task has completed
  • Call IMAPITable::WaitForCompletion.

    Calling WaitForCompletion allows the task to complete without interruption.


Tips for Better Table Performance

Because many of the table operations can be time-consuming and there is no way to indicate progress, it is helpful to use the following techniques for improving performance:

  • Make IMAPITable calls in the correct order.

    Clients and service providers can work with tables in a variety of ways. They can open the table and retrieve the data for all of the rows using the default column set and sort order. Alternatively, they can modify this default view of the table by changing the column set, changing the sort order, or establishing a restriction to narrow the table's scope. Table users that intend to perform one or more of these operations before retrieving any data should perform them in the following order:

    1. Define a column set with IMAPITable::SetColumns.
    2. Establish a restriction with IMAPITable::Restrict.
    3. Define a sort order with IMAPITable::SortTable.

    Performing these tasks in this order limits the number of rows and columns that will be sorted, thereby improving performance.

  • Delay an operation using the TBL_BATCH flag if possible.

    Setting the TBL_BATCH flag on a method allows the table implementer to collect several calls before acting on any one of them. Rather than make potentially many calls to a remote server, a table implementer can make one, performing all the operations at one time. The results of the operations are not evaluated until they are needed. For example, when a client calls IMAPITable::Restrict to specify a restriction with the TBL_BATCH flag set, the restriction need not go into effect until the client calls IMAPITable::QueryRows to retrieve the data. This allows the table implementer to combine the work of two calls into one.

    Table users that take advantage of the TBL_BATCH flag should be aware that error handling under these conditions can be more complex. Because handling the errors from a delayed operation is similar to handling the errors when the MAPI_DEFERRED_ERRORS flag is set, see Deferring Errors for more information.

  • Keep a cache of commonly used properties.

    Service providers implementing tables can lessen the time it takes to create a view by caching copies of commonly used object properties. Keeping a copy of these properties in memory saves having to retrieve them from the object each time the view must be rebuilt.


Forms

After reading this overview of the MAPI form architecture, you will have an understanding of what MAPI forms are and how they interact with other components of the MAPI subsystem. The purpose of this section is to give you the conceptual knowledge you need to implement your own MAPI form servers.

Before reading this section, you should familiarize yourself with the material in the About MAPI Forms topic.

Note Because the MAPI form architecture is based on the OLE component object model, developing form server applications requires knowledge of OLE programming. For more information on OLE, see the COM and ActiveX Object Services section in the Platform SDK.


Form Servers

The user's perception of a form is usually a property sheet for a message or a data-entry form that enables users to enter structured information. However, it can be any user interface that is associated with a message class. From a programmer's point of view, a form consists of:

  • A type of MAPI message with its own message class and OLE identifier.
  • The executable file that implements the form server.
  • A collection of MAPI properties — custom or otherwise — that the form server uses. Some or all of these may be available to messaging clients for use.
  • The configuration file that describes the form and is used by the form manager.

Because forms are IMessage objects, they exhibit properties and behavior that is consistent with MAPI message objects. However, because forms can have custom properties, controls, and a display rendering that is application-specific, the MAPI interfaces that forms use are generic enough to permit any sort of interface that is needed. The actual definition of a form is stored in a form library, which is discussed later in this section.

Note More accurately, all messages are instances of MAPI forms. However, it is usually easier to think of custom forms as special cases of messages, since forms for composing and reading typical e-mail messages are the most commonly used forms. The fact that all messages are really just forms gives custom forms the same status as any other message in the MAPI system.

Every form has a set of properties, some of which are visible within the form's user interface. Usually, properties are matched to fields within the form's user interface. For example, a purchase order form might have the fields Item, Description, Price, Tax, and Subtotal. These fields are simply visual renderings of form properties of the same names. Clients ascertain which properties are supported by a particular message class through the IMAPIFormInfo::CalcFormPropSet method, which is implemented by the MAPI form manager.

Like basic messages, MAPI forms can contain all the standard message properties such as the sender, the intended recipient, and when the message was sent. Forms can also contain any number of custom properties that are specific to the form. For example a "Bug Report" form might contain custom properties for Bug Type, Bug Severity, and Product Version.

To create a form you must implement a form server. The form server is the executable file that is loaded when a messaging client needs to display a message that is the type supported by the form server. The form server in turn creates form objects as necessary to display specific messages and handle user interactions with those messages.

Every form server has a configuration file associated with it. This file contains information that describes the form server for the benefit of the form manager. The form manager uses this information when installing the form server into a form library.

For details on creating the parts of a form, see Developing MAPI Form Servers.

Form servers adhere to the OLE component object model (COM). Form servers run as standalone executables, not as in-proc servers. For more information, see the COM and ActiveX Object Services section in the Platform SDK.

Each form server is identified by a unique OLE class identifier often written as just CLSID. There is always a one-to-one mapping between a class identifier and it's message class. This does not mean, however, that a form server can only work with messages of one message class. If no form server is available to service a message of a particular class, the form manager being used should attempt to find a form server for a message class higher in the message class hierarchy; the default form manager supplied with the MAPI SDK does this. Such a form server will probably be able to render only a subset of the message's properties (the ones supported by the superclass), but it will be better than nothing. What happens when no matching form server is found at all is an implementation detail specific to the form manager being used; the default form manager does not open messages when this happens.

For more information, see Message Classes.


Form Verbs

A form's user interface typically offers menu items or controls that enable users to take some kind of action with the form. It is the form server's job to handle these user actions. This interface is implemented using standard Win32 APIs; writing one is just like writing other interfaces for regular Win32 programs.

Often, user actions are associated with verbs. A verb is the name for an action that is specific to a certain message class. For example, Reply is a verb that is implemented by many form servers, each of which may have a different interpretation of that verb. Verbs are sometimes referred to as commands.

Note Not all menu items and controls on a form correspond to a verb. For example, a Cancel button does not correspond to a Cancel verb within the form server. Usually, verbs are associated with actions that are specific to a particular message class or a set of message classes. Although different message classes can support different sets of verbs, all support at least the Open verb, which displays the form's user interface and loads it with the message's property values.

Verbs may take no parameters. Forms that export commands with variable parameters must use the Automation mechanisms.

Clients can determine which verbs are supported by a particular message class through the IMAPIFormInfo::CalcVerbSet method, which is implemented by the MAPI form manager. The form manager gets this information from the form's configuration file. The verb set returned by this method is used by the client to show the user which commands can be executed on a message. For example, a client might enable users to click the right mouse button over a message to display verbs applicable to that message.


Form Objects

Form objects are created dynamically by form servers in order to display specific messages and allow users to interact with them. A form object is, therefore, usually an instantiation of the IMAPIForm-derived class implemented by the form server. When a client application opens a message, the form server for that message class creates a form object to handle the message. The form object then creates its interface and displays the properties of the message in it. The form object and its interface persists until the user closes it. The form object handles any changes to the values of the message's properties.

Additionally, the MAPI form interfaces define a mechanism by which one form object can load and display a series of messages. This is an efficiency mechanism, as it avoids needless destruction and creation of message objects and their interfaces. When requested by the messaging client to load a different message, the form object should save any changes to the current message's properties.

For information on a client application's perspective of form objects, see About Custom Form Objects.


The Form Manager

A form manager is an object that implements the IMAPIFormMgr interface. Most organizations will use the form manager supplied with MAPI, referred to as the default form manager. However, an organization can replace the default form manager with a custom form manager if desired. The form manager takes care of locating forms within form libraries, loading forms in response to user requests, and installing forms into a user's local form library, folder form library, or personal form library.

For a user to interact with a message, an instance of the form server for the message's message class must be created and activated to display the message and carry out the requested operation on the message. As described in the topic Form Libraries, a form's implementation can exist in several different locations (form libraries) and there is no guarantee that a form or its server will be locally available or in a running state when a user wants to interact with it. The form manager takes care of the details of locating and activating the form.

Clients use services provided by the form manager to find and activate forms. The IMAPIFormMgr interface is implemented by the form manager and is called by clients to access its services. The form manager is an essential component because it hides almost all the details of finding and activating forms from messaging clients.

When loading form servers, the default form manager loads the form from the first form library in which an implementation for the form's message class is found. The default form manager searches the form libraries in the following order:

  1. The user's local form library. This form library is searched first because it provides the fastest access to a form's implementation if the implementation is installed in the local form library.
  2. The folder form library of the message's container — the folder that the message being loaded is stored in.
  3. The user's personal form library.

A custom form manager can search the available form libraries in any order, or can implement other form libraries such as an organization-wide form library. For more details on form libraries, see Form Libraries.


Capabilities Not Supported by Form Managers

For performance reasons, the following features aren't supported by the default form manager but may be supported by custom form managers:

  • A hierarchy that enables forms to be grouped or categorized within a form library. A form library is essentially a flat-file database of forms.
  • Access control for categories of forms, corresponding to message classes or superclasses.
  • Support for multiple language versions of the same form in a single form library.

These are entirely implementation issues. There is nothing to prevent a custom form manager from implementing these features.

The MAPI form architecture does not support multiple form managers running concurrently. Although MAPI supports multiple concurrent message store providers, transport providers, and address book providers, only a single form manager is supported.

Because only one form manager may be running at once, if you implement a custom form manager you will have to re-implement any functionality from the default form manager that you need. Since your custom form manager will entirely replace the default form manager, capabilities of the default form manager will be unavailable unless they are duplicated in your custom form manager.


Disk Instances and Cache Tables

To activate a form, its executable files must be available on the user's computer. If they are not available, they must be copied from the form library to the local disk. To do this, the default form manager creates a subdirectory within the user's Windows directory to contain the form's executable files (.EXEs, .HLPs). This directory is referred to as the disk instance of the form.

The default form manager maintains a table of all disk instances so that if a disk instance already exists it can be used without having to copy files from the form library to the user's disk. The table of disk instances is managed as a least frequently used cache. If a new disk instance is needed, it is copied to the user's computer, replacing the least frequently used disk instance. The disk instance cache table is then updated to reflect the latest configuration. The size of the disk cache is a user-configurable option, enabling users to balance speed with available disk capacity.

In addition to the disk instance cache, the default form manager maintains a running instance table that lists all running instances of form servers on the user's computer. This uses MAPI's ability to keep idle form instances running in an invisible state until a form of that form server's message class is activated. In other words, form servers can be cached in RAM to minimize the number of times a form's executable must be located within a form library and loaded into memory from disk or over the network. Like the disk instance cache, the running instance cache behaves in a least frequently used fashion so that a running form instance can be purged from the cache to make room for another form instance. This cache is searched for a running instance of a form server before the form libraries are searched for the form server.

Note The default form manager displays a progress indicator when installing a form on a user's workstation, enabling the user to cancel the operation. This is especially useful if the user's connection to the form server's executable file is over a low bandwidth network.


Platform Independence

Form libraries are independent of the platform on which the forms in them are used. This means that a single form definition in a form library can include versions of the form for multiple platforms such as Windows for Workgroups, Windows NT, and Macintosh. However, if a form does not support the platform that a user is using, the default form manager will attempt to find a form server for a superclass of the message being opened to view the form instead, provided that any are available which do support the user's platform.


Form Libraries

To help organize form servers and make them easily accessible to client applications, the MAPI form architecture includes form libraries, which support the installation, administration, replication, and use of form servers. Form libraries are repositories of form servers and configuration information about them that the form manager uses when loading form servers.

Note Early in the history of MAPI, form libraries were called "registries." Because of this, the term "registry" has persisted in some form-related MAPI interfaces, properties, configuration file entries, and so forth. If your application's interface requires use of one of these terms, you should use the term "library" exclusively.


Form Storage

Although it is not necessary to know all the details of how forms are physically stored, it is useful to understand a few of the main concepts. Therefore, before describing the three types of form libraries supported by the default form manager, this topic gives an overview of how forms are stored.

Form definitions can be physically stored within folders in one or more MAPI message stores. Every MAPI folder can be thought of as having two areas for storing message objects: the standard part and the associated part. The standard part of the folder includes the messages and folders that users manipulate.

The associated part includes hidden message objects that are associated with the folder, including form definitions, views, rule templates, reply templates, and so on. This alternate part is called the folder associated contents table, and the set of messages in the associated contents table is referred to as the folder-associated information. The hidden messages are an integral part of the folder and are copied along with the standard folder contents when the folder is copied. Although physically stored as messages, information in a folder's associated contents table behaves more like properties than like viewable messages. Any folder object that supports an associated contents table is capable of storing custom forms. The IMAPIContainer::GetContentsTable method can return either the standard contents or the associated contents of the folder, depending on the value of the method's ulflags parameter.

A form library consists of form definitions stored in a folder's associated contents table. The form definition includes the form's properties, the actions the form supports, and even the form server executable file, which is stored as one or more message attachments.

Additionally, forms can be stored in any file or location that the form manager being used supports. The default form manager stores form servers in MAPI folders, but a custom form manager could implement its own storage for form servers.

A form can have multiple user interfaces that are bound to its message class. For example, a form can have separate Compose and Read interfaces. The form takes care of invoking the proper interface for different user requests, depending on which of the form's verbs is being called. For example, if your form server has separate composing and reading interfaces, the Compose interface can be opened automatically when the user creates a new message of the form's message class and the Read interface can be opened automatically when the user opens an existing message of the form's message class.

Most of the information stored within a form definition is available by invoking the IMAPIFormInfo::IMAPIProp method on an IMAPIFormInfo object. The IMAPIFormInfo interface simplifies access to form information by calling all the MAPI folder and message methods needed to retrieve the information. An IMAPIFormInfo object can be obtained by calling the IMAPIFormContainer::ResolveMessageClass method.

The three types of form libraries are described in the topics Local Form Libraries, Folder Form Libraries and Personal Form Libraries.


Local Form Libraries

Local form libraries are stored directly on a user's machine, usually in a file called FRMCACHE.DAT in the %WINDOWS%\FORMS directory. Client applications can access forms in the local form library without accessing any network resources. Local form libraries are an exception to the rule that forms are stored in associated contents tables, since the local form library is simply a file on disk that is not part of any MAPI folder heirarchy.


Folder Form Libraries

In some cases, you might want to associate one or more forms with a specific folder. For example, employees in your organization could all have a Progress Report folder in their personal message store for creating and storing progress reports. Because the progress report is specific to each user's Progress Report folder, it might not be appropriate to store the progress report form in the system wide form library. However, a copy of the progress report form can be kept in the associated contents table of each user's Progress Report folder. This restricts the user from using progress report forms outside of the designated folder.

Conceptually, there is one folder form library for every folder in a message store, even if no form servers are installed in it. Folder form libraries are implemented like other form libraries — they are stored as associated contents tables in the alternate part of the folder. Because folder form libraries are contained within the folder, they are copied along with their parent folder in copy operations.


Personal Form Libraries

As its name suggests, personal form libraries contain forms of interest to a particular user. A user's personal form library is the form library associated with the default message store identified in the user's profile; each profile installed on a workstation can use a separate default store, and therefore, a separate personal form library. A personal form library can contain copies of forms that are also contained in other form libraries in addition to other forms.

A personal form library is implemented in the associated contents table of the root folder in a user's default message store — whether that resides on a server or locally on the user's workstation is immaterial. If the user's default message store is stored on the user's workstation, personal form libraries offer enhanced performance by enabling applications to access forms locally rather than over the network. It also makes forms available to users working offline, which can occur when users want to take their forms with them on portable computers and are without access to a network.

The properties and underlying implementation of personal form library entries include a "Container ID" property that identifies a master container that the local entry must be synchronized with. This can be the identifier of an arbitrary folder that contains forms. This is useful if you are using a custom form manager that supports some sort of organization-wide form library; the form manager would take care of synchronizing the forms stored in the personal form library and the organization-wide form library. This would probably happen when the form manager was loaded, but could theoretically happen at any time.


Forms and MAPI Client Applications

Since all MAPI messages are instances of forms, client applications display and interact with form objects just as they do with other message objects. Client applications that use the MAPI form interfaces can provide additional interaction with form objects. Client applications can use any special verbs defined by a form to provide users with the full range of interactions intended by the form's designer. Clients can also use any custom properties that the form server exposes to help users sort, preview, or otherwise manage forms in the client's interface.

For more information, see Handling MAPI Forms.


MAPI Form Interfaces

MAPI defines the following interfaces relating to forms:

Interface name | Description
IMAPIForm | Manipulates form objects and handles form object commands.
IMAPIFormAdviseSink | Determines if the form object can handle the next message and changes the next or previous state of the form object.
IMAPIFormContainer | Supports installation, deinstallation, and resolution of form servers against a specific form container.
IMAPIFormFactory | Supports the use of configurable run-time form servers.
IMAPIFormInfo | Enables client applications to work with properties that are specific to a message class.
IMAPIFormMgr | Enables client applications to get information about form servers, activates form servers, and installs form servers in the messaging system.
IMAPIMessageSite | Used to manipulate messages associated with form objects.
IMAPIViewAdviseSink | Notifies client applications that an event has occurred in the form object.
IMAPIViewContext | Used to respond to Next, Previous, and Delete commands in the form object.
IPersistMessage | Used to save, initialize, and load form objects to and from message storage.

For more information on the methods of the MAPI form interfaces, see the documentation for these interfaces. You do not have to implement all of the MAPI form interfaces in order to create a custom form. A form itself requires only that you implement the IPersistMessage, IMAPIForm, and IMAPIFormAdviseSink interfaces. Additionally, it is also a good idea to implement IMAPIFormFactory and IMAPIFormInfo. IMAPIFormFactory is useful for OLE compliance, and IMAPIFormInfo allows well-written client applications to make better use of your forms.

Note Strictly speaking, IMAPIFormAdviseSink is an optional interface. However, it is strongly recommended that you implement it in your form servers. This interface is critical to efficient interaction between messaging clients and form servers, especially when several messages of your form server's message class are being dealt with.


MAPI Programming Basics

The topics in this section apply to developers of client applications and service providers. These topics are arranged in order of importance. That is, topics that are critical to all programmers appear first and topics that are either of minimal importance or do not apply to all programmers appear last.


Entry Identifiers

Entry identifiers are pieces of binary data stored in an ENTRYID structure that are used to uniquely identify and open a MAPI object. Most MAPI objects have entry identifiers. Entry identifiers for objects are analogous to file names for files. However, they are not transmittable and cannot be used on systems other than the system they originated on.

Message store providers assign them to message stores, folders, and messages; address book providers assign them to address book containers, distribution lists, and messaging users. Entry identifiers are also used for opening an object represented by a row in a table, such as a status object in the status table. Objects store their entry identifiers in their PR_ENTRYID property.

Whereas service providers create, assign, and examine entry identifiers, client applications use them only as tools for opening objects. To clients, entry identifiers are opaque pieces of binary data and have nothing to do with the underlying messaging system.

Clients call an object's IMAPIProp::GetProps method to retrieve its PR_ENTRYID property or a table's IMAPITable::QueryColumns method to retrieve the column holding the PR_ENTRYID property.

Entry identifiers are passed as parameters to OpenEntry and to CompareEntryIDs. With OpenEntry, clients can open an object. With CompareEntryIDs, clients can compare two entry identifiers to determine if they refer to the same object. Because entry identifiers are not necessarily binary comparable, clients must compare them with the CompareEntryIDs method. CompareEntryIDs and OpenEntry are implemented with several MAPI objects.

Clients should always pass naturally aligned entry identifiers in their calls to service providers because although service providers should handle entry identifiers that are arbitrarily aligned, this is not always the case. A naturally aligned memory address allows the computer to access any data type it supports at that address without generating an alignment fault. The natural alignment factor is typically the same alignment factor used by the system memory allocator and is usually 8 bytes.

Entry identifiers come in two types: short-term and long-term. Short-term entry identifiers are faster to construct, but their uniqueness is guaranteed only over the life of the current session on the current workstation. Long-term entry identifiers have a more prolonged lifespan. Short-term entry identifiers are used primarily for rows in tables and entries in dialog boxes whereas long-term entry identifiers are used for many objects such as messages, folders, and distribution lists.


Constructing Entry Identifiers

Entry identifiers are constructed with the ENTRYID structure. The ENTRYID structure is made up of a flag that describes the attributes of the entry identifier and the actual entry identifier. The ENTRYID structure is defined as follows:

typedef struct
{
    BYTE        abFlags[4];
    BYTE        ab[MAPI_DIM];
}  ENTRYID, FAR *LPENTRYID;

MAPI_DIM is a constant that is defined in the MAPIDEFS.H header file.

The first byte of the 4-byte abFlags member describes the type and use of the entry identifier and can have the following values:

MAPI_NOTRECIP

MAPI_NOTRESERVED

MAPI_NOW

MAPI_SHORTTERM

MAPI_THISSESSION

MAPI_NOTRESERVED, when set, indicates that the entry identifier can be used by other service providers for other objects. The MAPI_NOTRECIP value indicates whether or not the entry identifier can be applied to a message recipient. When MAPI_NOW is set, the entry identifier can only be used at the present time, and when MAPI_THIS_SESSION is set, the entry identifier can only be used for the current session. MAPI_SHORTTERM identifies the entry identifier as a short-term identifier.

Clients expect to be able to check this first abFlags byte to determine the entry identifier's longevity. A zero in abFlags[0] indicates a long-term identifier and a nonzero indicates a short-term identifier. The last three bytes of the abFlags member must be zero.

The ab member of entry identifiers created by address book and message store providers is made up of two pieces: a 16-byte MAPIUID that identifies the service provider and a piece to identify the object. MAPIUID is a structure that contains a globally unique identifier, or GUID. A GUID is a byte order independent identifier which can be created using the Microsoft utility UUIDGEN.EXE.

A service provider registers its MAPIUID structure with MAPI during the logon process in a call to IMAPISupport::SetProviderUID. When a client calls an OpenEntry method to access an object, MAPI uses the MAPIUID structure to determine which service provider can provide that access. Service providers should use the same MAPIUID structure for all versions of their DLL. This enables clients with the newer version to respond to messages sent and saved with the older version. Service providers that are using a profile that must work on two different processors, each with a different byte order, use a MAPIUID structure to differentiate between objects.

The rest of the ab member after the 16-byte MAPIUID contains service provider-specific binary data for identifying particular objects. There is no fixed size for this portion of the entry identifier. It can be any size, within reason.

A service provider typically includes the following in this part of its entry identifiers:

  • Version information

    Because it is common for a service provider to change the format of its entry identifiers from version to version, storing version information makes it possible to quickly determine how to decipher any entry identifier.

  • Location information

    Location information is data that gives a service provider an indicator of how to locate the object represented by the entry identifier. For example, a service provider can store the disk offset for the last place in a data file that the object was stored. Because this type of information can change over time, service providers should provide multiple ways for locating objects in their entry identifiers.

Service providers are encouraged not to recycle their entry identifiers, but they can. If it is necessary to reuse an entry identifier, service providers should make the time period that elapses between the initial use and the reuse as long as possible. Also, the entry identifier should be reassigned to another object of the same type. That is, a particular entry identifier should not be associated first with a message and then with a folder.


Short-Term Entry Identifiers

A short-term entry identifier is assigned by a service provider to an object when the identifier must be constructed quickly and does not need to last over time or distance. The uniqueness of a short-term entry identifier is guaranteed only over the life of the current session on the current workstation. Typically, a short-term entry identifier is valid only until the object that it represents is released.

Short-term entry identifiers are assigned to rows in tables and to entries in dialog boxes, where it is necessary to provide data quickly for browsing. For example, message store providers assign short-term entry identifiers to rows of messages in a contents table and to recipients in a recipients table. Clients can use these short-term entry identifiers to open the objects represented by the table rows. However, unlike long-term entry identifiers that can be used with any of the OpenEntry methods, short-term entry identifiers should be used with the container's OpenEntry method.

The most common ways to implement short-term entry identifiers include:

  • Making the short-term entry identifiers the same as the long-term identifiers, leaving all of the flags unset.
  • Making the short-term entry identifiers different from the long-term identifiers, setting all of the flags.

Clients can identify a short-term entry identifier of the second type by examining its abFlags member as follows:

abFlags[0] = 0xFF;

Some service providers create short-term entry identifiers that have greater validity by clearing one or more flags. For example, the following abFlags members represent short-term entry identifiers that can be used for multiple days or for multiple sessions:

abFlags[0] = 0xFF & ~MAPI_NOW;
abFlags[0] = 0xFF & ~MAPI_THISSESSION;

Clients quickly acquire, use, and discard short-term entry identifiers. For the most part, they can be used in the same manner as long-term entry identifiers. They can be retrieved from a table, passed to OpenEntry, and compared with CompareEntryIDs. The one exception is that they are never returned from IMAPIProp::GetProps. The properties returned from GetProps are always long-term entry identifiers.


Long-Term Entry Identifiers

A long-term entry identifier is assigned by a service provider to an object when an object requires an identifier with a prolonged lifespan. Long-term entry identifiers are always valid for weeks or months and can be valid on other workstations, depending on the provider. The long-term identifiers created by address book providers for custom recipients are universally valid.

Long-term entry identifiers are assigned to message stores, folders, messages, address book containers, messaging users, and distribution lists. When client applications call the IMAPIProp::GetProps method of these objects, it is always a long-term entry identifier that is returned.

Because long-term entry identifiers must be unique across all message stores in the active profile, when a message or folder is copied from one message store to another, it must be assigned a new entry identifier. However, when a message store object is moved, whether or not the original entry identifier remains valid is up to the message store provider implementing the move. Some service providers assign new entry identifiers to moved objects; others do not. If there is a change, the new entry identifier will be included in the information passed to clients when they are notified of the move.

Typically, message store providers implement the following behavior when moving folders:

  • When moving a folder from one message store to another store of a different type, the entry identifier is guaranteed to change.
  • When moving a folder from one message store to another store of the same type, the entry identifier almost always changes.
  • When moving a folder to another location within the same message store, the entry identifier might or might not change, depending on the message store provider.

Note Renaming a folder without changing its parent usually does not cause the entry identifier to change.


Record and Search Keys

Record keys and search keys are binary identifiers that are assigned to many MAPI objects. Unlike an object's entry identifier, its record or search key is directly comparable as well as transmittable.

A record key is used to compare two objects. Message store and address book objects are required to have record keys, stored in their PR_RECORD_KEY property. Because a record key identifies an object and not its data, every instance of an object has a unique record key. The scope of a record key is the message store for folders and messages and the set of top-level containers provided by MAPI for use in the integrated address book for address book containers, messaging users, and distribution lists.

Record keys can be duplicated in another resource. For example, different messages in two different message stores can have the same record key. This is different from long-term entry identifiers; because they contain a reference to the service provider, they have a wider scope. A message store's record key is similar in scope to a long-term entry identifier; it should be unique across all message store providers. To ensure this uniqueness, message store providers typically set their record key to a value that is the combination of their PR_MDB_PROVIDER property and an identifier that is unique to the message store.

A search key is used to compare the data in two objects. An object's search key is stored in its PR_SEARCH_KEY property. Because a search key represents an object's data and not the object itself, two different objects with the same data can have the same search key. When an object is copied, for example, both the original object and its copy have the same data and the same search key.

Messages and messaging users have search keys. The search key of a message is a unique identifier of the message's data. Message store providers furnish a message's PR_SEARCH_KEY property at message creation time. The search key of an address book entry is computed from its address type (PR_ADDRTYPE) and address (PR_EMAIL_ADDRESS). If the address book entry is writeable, its search key might not be available until the address type and address have been set using IMAPIProp::SetProps and the entry saved using IMAPIProp::SaveChanges. When these address properties change, it is possible for the corresponding search key not to be synchronized with the new values until the changes have been committed with a SaveChanges call.

The value of an object's record key can be the same as or different from the value of its search key, depending on the service provider. Some service providers use the same value for an object's search key, record key, and its entry identifier. Other service providers assign unique values for each of its objects' identifiers.


Folders

Folders are MAPI objects that serve as the basic unit of organization for messages. Arranged hierarchically, folders can contain messages and other folders. Folders make it easier to locate and work with messages.

Folders implement the IMAPIFolder interface, which indirectly inherits from IUnknown through IMAPIContainer and IMAPIProp. Clients use IMAPIFolder to create, copy, and delete messages and folders, to retrieve and set message status, and to set or clear the read flag for a message. Although message store providers are required to support all the methods in IMAPIFolder, some of them introduce a level of complexity that message store providers might want to avoid. MAPI saves message store providers some work by implementing some of the more complex folder functionality in the IMAPISupport interface. Rather than implementing their own copy methods, for example, message store providers can call the copy methods in the support object and get the same results.

There are three kinds of folders:

  • Root folders
  • Generic folders
  • Search-results folders

Every message store has at least a root folder. The root folder appears at the top of the hierarchy and contains messages and other folders. Root folders cannot be moved, copied, renamed, or deleted. There is only one root folder for each message store.

Most other folders are generic folders. Like root folders, generic folders contain messages and other folders. Unlike root folders, they can be moved, copied, renamed, and deleted. Generic folders can be created within the root folder or other generic folders. When a client creates a generic folder within another folder, the new folder is called a subfolder, or child folder. The folder in which the new folder is placed is referred to as the parent folder of the new folder. Generic folders that have the same parent are called sibling folders. Both sibling and non-sibling folders may or may not have unique names, depending on the message store provider. Message store providers that require sibling folders to have unique names return the error value MAPI_E_COLLISION when a client attempts to create two folders within the same parent with the same name.

A search-results folder contains links to messages that match a set of predefined criteria. Because search-results folders contain links rather than actual messages, they are in effect read-only. They cannot contain other folders or have messages or folders moved or copied into them. They cannot have new messages created in them; and they themselves cannot be moved, copied, or renamed. When a message is deleted from a search-results folder, it is actually deleted from the folder that contains the message.

Folder type is stored in the PR_FOLDER_TYPE property. Every folder has this property set to either FOLDER_GENERIC, FOLDER_ROOT, or FOLDER_SEARCH, depending on its type.

Every folder has one entry identifier and one record key. The entry identifier, PR_ENTRYID, is used by clients and service providers to open the folder. The record key, PR_RECORD_KEY, is a binary value that is used to compare the folder with other folders.

A folder has other properties to identify related folders and the message store. The following properties are required:

PR_PARENT_ENTRYID

PR_STORE_ENTRYID

PR_STORE_RECORD_KEY

Some folders support the PR_ACCESS property which describes the type of operations a user can perform. For example, one of the valid settings for PR_ACCESS is MAPI_ACCESS_DELETE, indicating that the folder can be removed. Another setting, MAPI_ACCESS_MODIFY, indicates that the folder should be modifiable.

For a complete list of required folder properties, see IMAPIFolder.


IPM Subtree

MAPI creates a tree of folders beneath the root folder of a message store for all clients that send messages to and receive messages from human rather than machine recipients. Messages exchanged between human recipients are known as interpersonal messages and this tree is known as the interpersonal message, or IPM, subtree. The IPM subtree consists of the following folders:

  • Inbox
  • Outbox
  • Sent Items
  • Deleted Items

These are the default names and roles for each of these folders; a client can specify its own names if the default names are not appropriate. MAPI assigns default names and associations for these folders to keep messages from inadvertently disappearing if a client neglects to establish receive folders for messages.

The Inbox typically holds incoming messages and the Outbox holds outgoing, or "to be sent", messages. The Sent Items folder holds a copy of each sent message if the client has set the PR_SENTMAIL_ENTRYID property to the entry identifier of this folder. The Deleted Items folder contains messages marked for removal.


Special Folders

MAPI defines a few folders that are special because they serve predefined roles as default folders for certain types of messages and usually cannot be deleted, and have special entry identifier properties.

There are eight special folders, some that are part of the IPM subtree. MAPI creates these folders before a client receives access to its message store, after which the client might be able to delete them if necessary. Some message store providers allow deletion while others do not. The following table describes these folders:

Folder | Description
Outbox folder | Holds outgoing IPM messages.
Deleted Items folder | Holds IPM messages that are marked for deletion.
Sent Items folder | Holds IPM messages that have been sent.
IPM root folder | Holds folders for managing IPM messages.
Receive folder | Holds incoming messages for a particular message class.
Search-results root folder | Holds folders for managing search results.
Common views root folder | Holds folders for managing views for the message store.
Personal views root folder | Holds folders for managing views for a particular user.

The first four folders relate to the IPM subtree, a tree of folders created by MAPI when a message store is initialized. Default message stores for interactive messaging clients always include the IPM folder subtree and the other special folders in their folder hierarchy. Non-default message stores are only required to support the search-results root folder, the IPM subtree root folder, the Deleted Items folder, and the receive folder. To ensure that the IPM subtree folders exist and are valid, clients can call the HrValidateIPMSubtree function. HrValidateIPMSubtree checks the folders and recreates them if there is a problem.

The root folders for search results, common views, and personal views are not part of the IPM subtree; these folders are created in the root folder for the message store. The search-results root folder holds folders that support contents tables with messages that satisfy a set of search criteria. Although clients are allowed to create search-results folders in any folder, most clients designate a single root folder to be the parent of all the search-results folders created during the session.

The common views and personal views root folders hold messages that describe views, or preferred ways of presenting message and folder data. The common views root folder contains views that clients can use with any folder in the message store; the personal views folder contains views that have been defined by a particular user for a particular folder or folders.

Clients that work with IPM messages should create all folders and messages under the IPM subtree root folder, rather than the root folder of the message store. This gives non-IPM clients — the clients that deal with messages exchanged between machines or between humans and machines — an easy way to hide their messages from IPM clients.

MAPI assigns special entry identifier properties for these special folders. For a list of the special folder entry identifiers, see Opening a Folder.


Receive Folders

A receive folder holds inbound messages of a particular message class. Receive folder associations can be established by clients, by the message store provider, or by MAPI. MAPI has two default receive folders, the root folder of the message store and the Inbox folder of the IPM subtree. The root folder of the message store is the default receive folder for all IPC messages. The Inbox folder is created by MAPI for every new message store and acts as the default receive folder for the following message classes:

  • IPM
  • Report
  • Empty, or missing, class

All report messages, even those sent in response to an IPC message, are placed in the Inbox folder. IPC client applications that want to process their own reports must explicitly add a receive folder for the particular class of report. For example, if a client expects to receive messages with the class IPC.Paper.Order, it should call IMsgStore::SetReceiveFolder to establish a receive folder for reports with the class Report.IPC.Paper.Order.

Receive folder associations are based on the hierarchical organization of message classes. Clients can explicitly establish an association between a receive folder and a message class or use the MAPI default receive folders. Typically, clients designate one folder to receive messages for a base class and all of its subclasses. For example, a typical client would establish an association for messages with class MyClass. Then if the client received messages with classes MyClass.Home or MyClass.Home.Kitchen.Computer, these messages would go to the receive folder for the base class, MyClass.

There are three message store methods that clients use to work with receive folders:

IMsgStore::GetReceiveFolderTable

IMsgStore::GetReceiveFolder

IMsgStore::SetReceiveFolder

The receive folder table is a listing of information about all of the receive folders established for a message store. Its required column set includes the message class, record key, and entry identifier.

To retrieve a receive folder for a particular message class, clients pass the message class string to IMsgStore::GetReceiveFolder. The message store provider returns an entry identifier for the corresponding folder. To implement GetReceiveFolder, a message store provider should use an algorithm that selects the folder whose associated message class matches the longest possible prefix of the specified message class. For example, assume the message store has the following associations between receive folders and message classes in its receive folder table:

  • IPM messages are placed in the Inbox folder.
  • IPM.Note.Sample messages are placed in the Samples folder.

The following table shows how messages with various classes would be routed to the appropriate receive folder.

Inbound message class | Receive folder
IPM.Note.Sample.Simple | Samples folder
IPM.Note | Inbox folder
IPM.Timecard | Inbox folder
IPM.Note.Sample.Simple.Totally | Samples folder

Clients call SetReceiveFolder to make an explicit association between a particular message class and receive folder. When a message is delivered to an empty message class, MAPI places the message in the receive folder that is defined for some prefix of the empty class. For example, if your client has a receive folder established for messages with class IPM and a message with class IPM.Note.Test is delivered, this message will be placed in the receive folder for the IPM message class.

In calling SetReceiveFolder, clients typically pass the entry identifier of the new receive folder and a message class string. However, clients can pass in NULL for one or both of these parameters. The following table describes the behavior that results from specifying NULL for the message class and entry identifier parameters.

SetReceiveFolder parameter | Resulting behavior
Entry identifier set to NULL | Message store deletes the association between the specified message class and its existing receive folder. A new receive folder is not established. Subsequent calls to GetReceiveFolder with this message class will return the receive folder for some prefix of the message class, or for new message stores, the Inbox in the IPM subtree.
Message class set to NULL | Message store changes the association for the empty message class to the indicated folder. Incoming messages whose class is otherwise unrecognized will go to this folder.
Entry identifier and message class set to NULL | Message store deletes the class/folder association for the empty message class. This is not recommended because it typically results in inbound messages being placed in the root folder of the message store, a folder that is invisible to the client.

Although a message's class should never be empty, this can occur. It is the message store's responsibility to assign the message class to IPM for new outbound messages with an empty class and the transport provider's responsibility to assign IPM.Note as the class for inbound classless messages.


Search-Results Folders

A search-results folder holds links to messages in generic folders rather than the actual messages. Clients create a search-results folder by calling IMAPIFolder::CreateFolder with FOLDER_SEARCH as the ulFolderType parameter. Clients fill a search-results folder by setting up and applying search criteria, or rules that serve to filter out messages with particular characteristics. Search criteria are set up with the IMAPIContainer::SetSearchCriteria method. Clients build one or more SRestriction structures to represent the search criteria to be applied and pass them to SetSearchCriteria. Also specified is a list of folders indicating the search domain and a set of flags controlling details of how the search is performed.

SetSearchCriteria identifies the messages that match the specified restriction. The selected messages, the ones that satisfy the criteria, appear as links in the search-results folder. When the client calls IMAPIContainer::GetContentsTable to access the search-results folder's contents table, the selected messages appear in the table. Contents tables for search-results folders contain the same columns as contents tables for generic folders. However, for search-results folders, PR_PARENT_ENTRYID is the entry identifer of the folder where the linked message resides. Search-results folders are not considered parent folders.

Search-results folders have the following limits:

  • The only way that the contents of a search-results folder can be modified is through the IMAPIContainer::SetSearchCriteria call.
  • Messages cannot be moved or copied into or out of search-results folders.
  • Search-results folders cannot contain subfolders.
  • Clients cannot set search criteria on a search-results folder, making it the subject of a search.

It is possible, however, to modify the properties of a search-results folder and use it to delete a message. When a message is deleted from a search-results folder, it is actually deleted from the real folder. However, deleting the search-results folder has no impact on the messages inside; they remain in their generic folders.


Hidden Folders

Hidden folders are generic folders that clients create within the root folder of the message store rather than the root folder of an IPM subtree. Because these folders are not placed in an IPM subtree, they are generally hidden from the user's view by the message store provider. Hidden folders typically hold information relevant to the message store but irrelevant to the user. Clients create hidden folders to store, for example, additional information to be saved with the rest of the folder hierarchy.

MAPI expects all clients to be able to display, create, modify, and delete folders in an IPM subtree. Support for working with folders in other trees is considered optional. However, all message stores that can be used as the default store and that can send and receive messages should fully support hidden folders.


View Folders

View folders are root folders that contain associated information for describing alternative layouts for displaying the contents of IPM folders. View folders reside under the root for the message store and are therefore not visible in the typical client application. Not every message store includes view folders; only message stores that are configured to work as the default message store for the session must include them.

MAPI supports two view folders:

  • Common

    The common view folder holds views that are standard for the message store and can be used by any user of a client accessing the message store. The entry identifier for the common view folder is stored in the store's PR_COMMON_VIEWS_ENTRYID property.

  • Personal

    The personal view folder holds views that are defined by a particular user. MAPI defines the PR_VIEWS_ENTRYID property for holding the entry identifier of the personal view folder. With personal views, one user can look at a group of messages in order by sender listing only the subject and the date received and another user can look at the same group in date order listing subject, sender, and message size. Unlike the root folders for the common views and search-results folders, the personal view folder hierarchy is visible to the user.


Messages

Messages are MAPI objects that are transmitted from one client application to another through the MAPI spooler and service providers by way of a messaging system. Nearly every component in MAPI works with messages. Clients allow users to create, save, send, and delete messages as well as copy and move them from one folder to another. Message store providers are responsible for providing the means for message management and for delivering messages to the MAPI spooler or a transport provider. The MAPI spooler moves messages to an appropriate transport provider while transport providers handle the delivery and receipt of messages to and from a messaging system and set recipient and message option properties. Address book providers work indirectly with messages, supporting properties that are used to describe message recipients.

Messages are stored in folders within a message store, typically folders created within the Interpersonal Message (IPM) root folder. Messages are usually stored at the same level as the standard IPM Inbox, Sent Items, Deleted Items, and Outbox folders, or at lower levels in the hierarchy. However, messages can be stored outside the IPM subtree as well.

Messages created in the standard IPM subtree are messages with standard contents, or contents that are visible to the user of a client application. Notes and reports are examples of messages with standard contents. Messages can also be created with associated contents, or contents that are not visible in the typical client. Associated messages are examples of messages that are created in folders outside of the IPM subtree. Folders support two different contents tables to hold the different types of messages: a standard contents table for standard messages and an associated contents table for associated messages. Because MAPI does not set standards for the content of associated messages, they can contain arbitrary information.

A message can have additional data, in the form of a file, another message, or an OLE object, associated with it. This additional data, called an attachment, appears either as an icon or metafile in the message text. A message can have zero attachments, one attachment, or many attachments. Attachments are always transmitted with the message.

A message that is transmitted has one or more recipients, or addresses associated with a particular messaging system. Some recipients are entries in a container belonging to an address book provider in the current profile; other recipients are created solely to be used to transmit the message. Because recipients and attachments must be accessed through the message with which they are associated, a message's recipients and attachments are known as its subobjects.

Message store providers support messages, attachments, and recipients through methods in three interfaces:

Interface | Description
IMessage | Manages attachments and recipients, sends messages, sets read status.
IMAPIFolder | Creates, copies, moves messages and subfolders and manages message status.
IAttach | Manages attachment properties.


Message Classes

Every message has a message class property, PR_MESSAGE_CLASS, which identifies the type, purpose, or content of the message. PR_MESSAGE_CLASS is a required property on all new messages. A message's class determines the form that is used to present the message to the user and the folder for placing incoming messages.

Message classes are case-sensitive character strings that contain ASCII characters 32 through 127 and are delimited by periods, but cannot end with a period. Each string represents a level of subclassing and there is no limit to the number of levels allowed.

For example, most messages sent and received by client applications fall into the IPM message class, a broad category that describes all interpersonal messages, or messages that are meant to be read by a human user, rather than programmatically by a computer. Message store providers more precisely describe an IPM message by creating an IPM subclass. The IPM subclass inherits the properties of the IPM message class. Subclasses of the IPM class are named by concatenating other character strings onto the IPM identifier, such as IPM.Note to describe a note message and IPM.HelpRequest to describe a help message.

To handle the display and management of IPM messages, clients can use a standard form provided by MAPI. To handle the display and management of new message classes, client application developers have two options:

  1. They can create a new form with the set of forms interfaces defined by MAPI that can be used by a standard client.
  2. They can write their own client, a complete, standalone application.

Although clients should set the PR_MESSAGE_CLASS property for every outgoing message to a subclass of either IPM or IPC, the message store provider has the ultimate responsibility for setting it. Therefore, if a client sends a message without setting its message class, the message store provider sets it to the appropriate default value for the appropriate type of client. The default message class for interpersonal messaging clients is IPM; the default message class for interprocess communication clients is IPC.

Message classes have a length restriction of 255 characters. However, MAPI recommends that they not exceed 127 characters to support the message classes used in reports. Report message classes are based on the class of the original message, with two additions: a prefix and a suffix. The prefix REPORT indicates that the message is a report and the suffix indicates the type of report: DR (delivery report), NDR (nondelivery report), IPNRN (read report), or IPNNRN (nonread report). Note that these length restrictions are given in characters; on platforms that use a double-byte character set, the actual byte count might be higher.

Message store providers should return MAPI_E_INVALID_PARAMETER from their IMAPIProp::SetProps implementations when a client attempts to assign a string that exceeds the allowable limit for their message class.


Report Messages

Report messages present status information about a message to its sender. There are two general types of report messages:

  • Read status reports
  • Delivery status reports

Read status reports are initiated by message store providers through a call to the IMAPISupport::ReadReceipt method and sent to the recipient represented by the entry identifier in the PR_REPORT_ENTRYID property. Read status reports are not generated automatically; clients that want to receive them must explicitly request them.

A read report indicates that the read flag of a message has been set, which can occur when the message is opened, printed, moved, or copied. Whether or not a message store provider generates a read report in response to a move or copy operation depends on where the message is going. If it is being moved or copied to another message store, a read report will most likely always be sent. If it is being moved or copied within the current message store, a read report might or might not be sent.

A nonread report indicates that the read flag of a message is not set and that the message was not opened either before being placed in the Deleted Items folder or before the expiration of a time limit. Clients can call the IMessage::SetReadFlag or IMAPIFolder::SetReadFlags method to set or clear a message's read flag.

Delivery status is reflected in a delivery report, sent when a message has reached its intended recipient, and in a nondelivery report, sent when a message could not reach a recipient. Delivery status reports are sent to the recipient represented by the entry identifier in PR_REPORT_ENTRYID or to the sender if this property is not present.

Delivery reports are sent by request only and do not include the original message. Nondelivery reports are sent automatically unless a request is made to suppress them. Nondelivery reports include the original message as an attachment to enable the report's recipient to attempt a resend in case whatever blocked the delivery is no longer a problem. The attached message resembles the original as it existed when the IMessage::SubmitMessage method was called to send it initially.

One or more delivery status reports are generated by transport providers when they call the IMAPISupport::StatusRecips method. Transport providers compose a list of recipients for a message. Whether or not a recipient receives a report and the type of report that is generated depends on the following:

  • Delivery reports go to recipients that have set the PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED property to TRUE before the message has been placed in the message store.
  • Nondelivery reports go to recipients that have not set the PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED property to FALSE.

Almost all of the information necessary to display a nondelivery report is contained in the recipient table of the attached message. A few properties are from the report itself. For delivery reports, the necessary information is contained in the recipient table of the report and in a few report properties.

Reports are messages with distinct message classes, based on the class of the sent message. Most service providers use a naming convention whereby the message class is made up of several parts separated by periods. The first part is "Report" and the last part is a constant that represents the report type. The middle part is reserved for the class of the sent message. For example, because a delivery report uses the constant DR, the message class for a delivery report about an IPM.Note message would be Report.IPM.Note.DR.

The constants that represent the types of reports are:

Report type | Constant used in message class
Read | IPNRN
Nonread | IPNNRN
Delivery | DR
Nondelivery | NDR

Interactive clients can display report messages using standard forms provided by MAPI or custom forms that have been registered for the report's message class with the form manager. Clients receiving a nondelivery report for an IPM.Note message, for example, can display the standard MAPI form that presents a list of the failed recipients and a suggested reason for the failure and allows the user to resend the message if desired.


About Message Properties

MAPI divides message properties into three types:

  • Message content properties
  • Message transmission, or envelope, properties
  • Message recipient properties

Message content properties describe the text of a message. Every message class has its own set of content properties. MAPI defines content properties for note and report messages; it is up to the clients and message store providers that handle these classes of messages to set the properties appropriately for their implementations. PR_BODY and PR_RTF_COMPRESSED are examples of content properties for note messages. PR_BODY contains the unformatted contents of a note while PR_RTF_COMPRESSED contains the compressed version of a note's formatted contents.

For new message classes, clients can define content-specific properties in one of two ways:

  • Using property identifiers within the 0x6800 through 0x7BFF range.
  • Using named properties which have identifiers that fall in the 0x8000 through 0xFFFE range.

The identifier range for custom message class content properties is available to any client creating a custom message class. Therefore, one property identifier in this range can be used for multiple message classes. Users of properties in this range cannot make assumptions as to the behavior of the properties.

With named properties, clients create a name for each new property that is made up of a property set and either a character string or a numeric value and associate it with an identifier in the named property range. Users of named properties access them by name or identifier through the IMAPIProp methods GetIDsFromNames and GetNamesFromIDs.

Envelope properties provide information used to transmit a message from one recipient to another. As with message content properties, it is possible for clients or service providers to define their own envelope properties to supplement those defined by MAPI. Clients and transport providers set the envelope properties defined by MAPI based on the definition that MAPI provides. Transport providers that implement special features can define their own envelope properties to expose those features to clients. MAPI sets aside a range of property identifiers that can be used for these special provider-defined properties. Transport providers typically implement a special property page to display these properties and allow clients to edit them. PR_SUBJECT and PR_MESSAGE_CLASS are examples of envelope properties.

Recipient properties describe the destination for a sent message. A recipient can be a messaging user, distribution list, or a machine. Recipient properties are defined by MAPI and set by service providers. Some recipient properties are supported by address book providers for their messaging user and distribution list objects; other recipient properties are supported by clients, message store providers, or transport providers. For example, all recipients require an address and an address type; these are properties maintained by an address book provider when the recipient is stored in one of its containers. Recipients also have a type, PR_RECIPIENT_TYPE, which identifies a recipient as either a primary, carbon copy, or blind carbon copy recipient.

Many message properties are optional, meaning that clients cannot expect them to be available or set to valid values. Some message properties are required but available only when a message is in a particular state. For example, a newly created message is not required to have an entry identifier until after the message has been saved and is not required to have a message class until the message is ready to be submitted. Clients should always be prepared to handle the situation where a requested property is unavailable by checking the results of their IMAPIProp::GetProps and IMAPIProp::OpenProperty calls and by having default values ready as a backup.

Most message properties that are set by service providers are read-only to clients.

For a list of the most commonly used message properties, see Message Properties.


Required Properties for All Messages

The following table describes properties that clients can expect to set or see supported on messages of all classes.

Property | Description
PR_CREATION_TIME | Set by message store providers on outgoing messages.
PR_DISPLAY_BCC PR_DISPLAY_CC PR_DISPLAY_TO | Set by message store providers on outgoing messages.
PR_ENTRYID | Set by message store providers on outgoing messages.
PR_LAST_MODIFICATION_TIME | Set by message store providers on outgoing messages.
PR_MESSAGE_ATTACHMENTS | Set by message store providers on outgoing messages.
PR_MESSAGE_CLASS | Can be set by clients on outgoing messages; must be set by message store providers if not set by clients.
PR_MESSAGE_FLAGS | Set by clients on outgoing messages before they have been saved and message store providers after they have been saved.
PR_MESSAGE_RECIPIENTS | Set by message store providers on outgoing messages.
PR_MESSAGE_SIZE | Set by message store providers on outgoing messages.
PR_MESSAGE_CC_ME PR_MESSAGE_RECIP_ME PR_MESSAGE_TO_ME | Set by transport providers on incoming messages.
PR_NORMALIZED_SUBJECT | Set by message store providers on outgoing messages
PR_ORIGINATOR_AND_DL _EXPANSION_HISTORY PR_ORIGINATOR_CERTIFICATE PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED PR_ORIGINATOR_REQUESTED_ALTERNATE_RECIPIENT PR_ORIGINATOR_RETURN_ADDRESS | Set by transport providers on outgoing messages.
PR_PARENT_ENTRYID PR_PARENT_DISPLAY | Set by message store providers on outgoing messages.
PR_RCVD_REPRESENTING_ADDRTYPE PR_RCVD_REPRESENTING _EMAIL_ADDRESS PR_RCVD_REPRESENTING_ENTRYID PR_RCVD_REPRESENTING_NAME PR_RCVD_REPRESENTING_SEARCH_KEY | Set by transport providers on incoming messages.
PR_RECEIVED_BY_ADDRTYPE PR_RECEIVED_BY_EMAIL_ADDRESS PR_RECEIVED_BY_ENTRYID PR_RECEIVED_BY_NAME PR_RECEIVED_BY_SEARCH_KEY | Set by transport providers on incoming messages.
PR_RECIPIENT_TYPE | Set by message store providers on incoming messages.
PR_RECORD_KEY | Set by message store providers on outgoing messages.
PR_SEARCH_KEY | Set by message store providers on outgoing messages.
PR_SENDER_ADDRTYPE PR_SENDER_EMAIL_ADDRESS PR_SENDER_ENTRYID PR_SENDER_NAME PR_SENDER_SEARCH_KEY | Clients can set these properties on outgoing messages, but transport providers are required to set them.
PR_SENT_REPRESENTING_ADDRTYPE PR_SENT_REPRESENTING _EMAIL_ADDRESS PR_SENT_REPRESENTING_ENTRYID PR_SENT_REPRESENTING_NAME PR_SENT_REPRESENTING_SEARCH_KEY | Clients can set these properties on outgoing messages, but transport providers are required to set them.
PR_STORE_ENTRYID PR_STORE_RECORD_KEY | Set by message store providers on outgoing messages.


Required Report Message Properties

The following table describes properties that clients can expect to see supported on report messages.

Property | Description
PR_ORIGINAL_DISPLAY_BCC PR_ORIGINAL_DISPLAY_CC PR_ORIGINAL_DISPLAY_TO | Set by creator of report, usually MAPI.
PR_ORIGINAL_SUBJECT | Set by creator of report, usually MAPI.
PR_ORIGINAL_SUBMIT_TIME | Set by creator of report, usually MAPI.
PR_CONVERSATION_INDEX PR_CONVERSATION_TOPIC | Set by creator of report, usually MAPI.
PR_MESSAGE_CLASS | Set by creator of report, usually MAPI.
PR_REPORT_TEXT | Set by creator of report, usually MAPI.
PR_BODY | Set by client before report is displayed.
PR_REPORT_TIME | Set by creator of report, usually MAPI.
PR_ORIGINAL_DELIVERY_TIME | Set by creator of report, usually MAPI. For read status reports only.
PR_SUBJECT | Set by client before report is displayed.
PR_MESSAGE_DELIVERY_TIME | Set by creator of report, usually MAPI.
PR_REPORT_TAG | Set by creator of report, usually MAPI.
PR_SEARCH_KEY | Set by creator of report, usually MAPI.
PR_SENDER_ADDRTYPE PR_SENDER_EMAIL_ADDRESS PR_SENDER_ENTRYID PR_SENDER_NAME PR_SENDER_SEARCH_KEY | Set by creator of report, usually MAPI.


Optional Report Message Properties

The following properties sometimes appear with report messages:

PR_ORIGINAL_AUTHOR_ADDRTYPE
PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS
PR_ORIGINAL_AUTHOR_ENTRYID
PR_ORIGINAL_AUTHOR_NAME
PR_ORIGINAL_AUTHOR_SEARCH_KEY

PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE
PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS
PR_ORIGINAL_SENT_REPRESENTING_ENTRYID
PR_ORIGINAL_SENT_REPRESENTING_NAME
PR_ORIGINAL_SENT_REPRESENTING_SEARCH_KEY


Recipient Properties for All Messages

The following properties are typically present for all message recipients. PR_EMAIL_ADDRESS and PR_SEARCH_KEY are optional; all of the other properties are required.

PR_ADDRTYPE

PR_DISPLAY_NAME

PR_DISPLAY_TYPE

PR_EMAIL_ADDRESS

PR_ENTRYID

PR_OBJECT_TYPE

PR_SEARCH_KEY


Recipient Properties for Delivery Status Reports

The following properties are present for delivery status reports for recipients. PR_DELIVER_TIME is not used on nondelivery reports. PR_NDR_DIAG_CODE and PR_NDR_REASON_CODE are used only on nondelivery reports.

PR_DELIVER_TIME

PR_DISPLAY_NAME

PR_ENTRYID

PR_NDR_DIAG_CODE

PR_MESSAGE_CLASS

PR_NDR_REASON_CODE

PR_ORIGINAL_DISPLAY_NAME

PR_ORIGINAL_ENTRYID

PR_ORIGINAL_SEARCH_KEY

PR_RECIPIENT_TYPE

PR_REPORT_TEXT

PR_REPORT_TIME

PR_SEARCH_KEY

PR_DISPLAY_TYPE

PR_OBJECT_TYPE


Attachments

Some message store providers allow clients to associate added information in the form of files, OLE objects, messages, or binary data with messages. This added information is called a message's attachment. Because attachments are created, maintained, and accessed only through their messages, they are considered message subobjects. Rather than having an entry identifier for access, attachments have a sequential number known as an attachment number. This number uniquely identifies the attachment within its message, but not necessarily within the message store. Two different messages can have different attachments with the same attachment number. Attachment numbers are only valid as long as the message is open and are stored in the PR_ATTACH_NUM property.

To access summary information about all of a message's attachments, clients retrieve its attachment table. The attachment table includes information that clients can use to access an attachment directly, such as its attachment number and record key. Clients can retrieve an attachment table by:

  • Calling IMessage::GetAttachmentTable.
  • Calling IMAPIProp::OpenProperty.

Message store providers are expected to support both of these approaches. The OpenProperty approach requires that the caller specify IID_IMAPITable as the interface identifier and PR_MESSAGE_ATTACHMENTS as the property tag. PR_MESSAGE_ATTACHMENTS is a table object property that represents a message's attachment table. Message store providers are required to set PR_MESSAGE_ATTACHMENTS for each message and include it in the array of property tags returned from the IMAPIProp::GetPropList method.

PR_MESSAGE_ATTACHMENTS can be used:

  • With IMAPIProp::OpenProperty to access an attachment or recipient table.
  • With IMAPIProp::CopyTo or IMAPIProp::CopyProps to exclude or include attachments when copying.
  • In a subobject restriction to indicate that the child restriction should apply to attachments.

For more information, see Attachment Tables.


Recipients

Every message to be transmitted has one or more recipients, or a set of properties that describe where the message is to be delivered. Because recipients are only used in the context of a message, they are considered subobjects of a message rather than separate MAPI objects. Clients and providers work with recipients using the IMessage interface.

Clients access a message's recipients through its recipient table. Every message has a recipient table that contains summary information about each of its recipients. The columns included in the table depend on the state of the message. When a message is under composition, its recipients may only have three columns in the table:

  • Display name, or PR_DISPLAY_NAME
  • Recipient type, or PR_RECIPIENT_TYPE
  • Row identifier, or PR_ROWID

After the message has undergone the name resolution process, each recipient will also have an entry identifier, or PR_ENTRYID column. And when the message has been submitted, the rows in the recipient table will add two more columns:

  • Address type, or PR_ADDRTYPE
  • Transport responsibility, or PR_RESPONSIBILITY

Clients can retrieve a message's recipient table by calling its IMessage::GetRecipientTable method or its IMAPIProp::OpenProperty method. Message store providers are expected to support both of these approaches. The OpenProperty approach requires that the client specify IID_IMAPITable as the interface identifier and PR_MESSAGE_RECIPIENTS as the property tag. PR_MESSAGE_RECIPIENTS is a table object property that represents a message's recipient table. Message store providers are required to set PR_MESSAGE_RECIPIENTS for each message and include it in the array of property tags returned from the IMAPIProp::GetPropList method.

For more information about working with a recipient table, see Recipient Tables.

In addition to being used to access a recipient table, PR_MESSAGE_RECIPIENTS can be used:

  • With IMAPIProp::CopyTo or IMAPIProp::CopyProps to exclude or include recipients when copying.
  • In a subobject restriction to indicate that the child restiction should apply to recipients.

Clients can add recipients to a message by copying entries from the MAPI address book or by creating new entries. These new entries, called one-offs, can exist temporarily or be saved permanently in a modifiable container such as the personal address book (PAB). Whereas recipients that are taken from the address book have entry identifiers associated with their address book provider, one-off recipients have entry identifiers that are formatted by MAPI. Transport providers and clients associate one-off entry identifiers with various types of addresses.

Transport providers call IMAPISupport::CreateOneOff to create a one-off entry identifier for an address on an outgoing message when:

  • The address belongs to a gateway.
  • The address cannot be handled by an address book provider in the current profile.

Clients call IAddrBook::CreateOneOff to create a one-off entry identifier for an address on an incoming message when:

  • The address is formatted as a one-off address.
  • The address is formatted as an Internet address.

For more information about one-off entry identifiers and addresses, see One-Off Entry Identifiers and One-Off Addresses.

The properties of a recipient are a combination of address book properties and properties specific to recipients. All recipients have the base address properties, assigned by address book providers. When an entry is used as a recipient for an outgoing message, the base address properties are copied to the ADRLIST structure that holds the properties for all of a message's recipients. For more information about the base address properties, see Base Address Properties.

Two properties that are set specifically for recipients are PR_RECIPIENT_TYPE and PR_RESPONSIBILITY. PR_RECIPIENT_TYPE indicates whether a recipient is a primary, carbon copy, blind carbon copy, or a resend recipient. The first three types are assigned to recipients on messages that are being sent for the first time.

If a recipient does not receive the message and an attempt is made to resend it, the recipient is copied and its type is set to MAPI_P1 to indicate that it is a resend recipient. If only some of the recipients receive a message, their PR_RECIPIENT_TYPE properties are marked with the addition of the MAPI_SUBMITTED flag when the message is resent. Clients are required to handle primary recipients, or recipients with their PR_RECIPIENT_TYPE set to MAPI_TO. All other types are optional.

PR_RESPONSIBILITY is set to indicate to the transport provider whether or not it should handle sending to the recipient. When an outgoing message is first sent, all of the recipients set PR_RESPONSIBILITY to FALSE. As a transport provider claims responsibility for sending to one or more of the recipients, their PR_RESPONSIBILITY properties are set to TRUE.


Address Book

The integrated address book is an object that MAPI implements to provide access to an integrated collection of addressing information from all of the address book providers in the profile. With the address book, client applications and service providers do not have to differentiate between the unique addressing schemes of messaging systems. Instead, they can look up the addresses of any recipients in any messaging system, as long as the address book provider for the messaging system is installed.

The address book can be accessed programmatically, without user intervention, or interactively through the use of common dialog boxes. MAPI includes dialog boxes to display a summary list of the entries in the address book, detailed information about a particular recipient, a warning when a user creates a recipient that cannot be mapped to a unique address, and a set of template forms for creating new recipients.

The MAPI address book is similar in structure to a message store in that it is organized hierarchically. The address book provides access to three types of objects implemented by an address book provider:

  • Address book container object
  • Distribution list object
  • Messaging user object

Each of these types of objects is accessed through its unique entry identifier that is assigned by its address book provider.

Address book containers are similar to folders in that they hold objects of different types. An address book container can hold other address book containers as well as messaging user and distribution list objects. Address book containers are used to organize and store address book objects.

To achieve the address book's integrated appearance, address book providers expose zero, one, or more of their top-level containers to MAPI which merges them and displays the results under a single top-level container. Address book providers can choose to expose one set of containers for one type of messaging session and a different set for another session. It is also possible for address book providers to have no top-level containers and expose only a list of templates that can be used to create recipients.

Message recipients are implemented with messaging user and distribution list objects. Messaging users are individual recipients; distribution lists are group recipients. Each messaging user has a unique address of a particular type handled by a particular messaging system. A distribution list is a named collection of recipients. Distribution lists can contain messaging user objects and other distribution lists. When a user of a client application sends a message to a distribution list, the message is being sent to each of the list's messaging user members.

Messaging users and distribution lists have a set of five properties that are known as the base address properties. These are required properties and are briefly described as follows.

Base address property | Description
PR_ADDRTYPE | Type of address for the recipient. Each address type follows a particular format and is used with a particular messaging system.
PR_DISPLAY_NAME | Displayable name for the recipient.
PR_EMAIL_ADDRESS | Address of the recipient.
PR_ENTRYID | Entry identifier used to access the recipient.
PR_SEARCH_KEY | Binary comparable key used to identify the recipient.

MAPI defines many groups of properties that are variations of the base address properties. These other groups describe messaging users and distribution lists in different situations. For example, one group of properties describes the delegate sender of a message and another group the delegate recipient. For more information about these properties, see Base Address Properties.


Address Types

Every messaging user is associated with an address type, a character string describing the format of the user's address that is stored in the PR_ADDRTYPE property. Address types map to address formats. That is, by looking at a recipient's address type, client applications can determine how to format an address appropriate for the recipient. For example, the address type MS describes an address with three components separated by slashes as indicated by the following entry:

network/postoffice/mailbox

Likewise, the SMTP address type describes the standard Internet address:

username@companyname.com.

All address book entries must have a valid address type. Clients require their users to specify an address type when creating a type of custom recipient unsupported by the address book provider. For the entries that they support, address book providers are required to supply valid address types.

MAPI defines only one address type: MAPIPDL, which stands for personal distribution list. Microsoft publishes address type definitions for those messaging systems that it makes, such as MS. Other definitions are taken from the vendor or standards body that owns them. The complete list of address types is included in an appendix, Address Types.

To get a list of the address types supported by all of the transport providers in the session, clients call the IMAPISession::EnumAdrTypes method.


One-Off Addresses

One-off addresses are used to send messages to one-off recipients, recipients that do not have a corresponding entry in any of the session's address book containers. Clients can create one-off addresses when they add new entries to the address book or new recipients to the recipient list of an outgoing message. One-off addresses can be added to any container that is modifiable.

To create a one-off address, clients use a special template containing edit controls for entering all of the information that makes up a one-off address. One-off addresses, like addresses of other types, use a predefined format. The one-off address format is defined by MAPI as follows:

Display name[Address type:E-mail address]

There are six components to this format and some rules about quoting characters. The components are described in the following table.

Component | Usage | Description
Display name | Optional | If not present, IAddrBook::ResolveName uses the visible part of the e-mail address as the display name. May include blanks.
[ | Required | Delineates the start of the type and address information.
] | Required | Delineates the end of the type and address information. If anything other than white space follows this character, the entry is not treated as a custom recipient.
Address type | Required | Type of address; maps to a specific address format. See the appendix, Address Types.
: | Required | Separates the address type from the e-mail address.
E-mail address | Required | Address of the recipient. May include blanks.

MAPI uses particular sets of quoting characters to allow addresses to contain special characters such as comma (,), left bracket ([), and colon (:) and some untypeable characters such as the carriage return or line feed or any other hexadecimal equivalent. The quoting character is the backslash (\). Therefore, if clients or providers must insert a backslash in an address, they must preceed it with the quoting character ("\\").

Clients and service providers can use this quoting technique in any of the nonfixed, typeable fields. For example, the following entry translates to Bill Lee as the display name, MSPEER as the address type, and \\billll\in as the e-mail address:

Bill Lee[MSPEER:\\\\billl\in]

To insert special nontypeable characters, clients and service providers use a quoting character followed by an x and two hexadecimal digits to represent their hexadecimal equivalent. For example, if an address has a nontypeable character that equates to a carriage return, (\0d) in hexadecimal, a client would enter them as:

Fax Recipient[fax:recipient\x0dbuilding\x0doffice\x0d555-1212\x0d]

IAddrBook::ResolveName also automatically parses most SMTP addresses, looking for addresses with the following format:

XXX@YYY.ZZZ

Although not all of the possible RFC822 formats are handled, this automatic parsing is adequate for most users. ResolveName includes this functionality to allow users to enter SMTP addresses directly into a message and have that message go to the Internet user. The XXX, YYY, and ZZZ components of the address can be one or more characters. The at sign (@) cannot be included in either the XXX, YYY, or ZZZ address components and the YYY component also cannot include the period. Because the following characters are special characters in SMTP addresses, MAPI automatically converts a display name containing these characters into a one-off address:

  • >>
  • @
  • <>
  • .

Every one-off address is assigned a corresponding one-off entry identifier. To make this assignment, clients call IAddrBook::CreateOneOff and transport providers call IMAPISupport::CreateOneOff. When processing incoming messages, transport providers create one-off entry identifiers for gateway addresses and for addresses that cannot be handled by the transport's associated address book providers. Transport providers check the type of each address in a message to determine if it can be handled by an address book provider associated with the transport. If it cannot, transport providers call IMAPISupport::CreateOneOff to associate the address with a one-off entry identifier.

One-off entry identifiers include the following information in the following order:

  1. MAPIUID
  2. Version
  3. Flags
  4. Display name
  5. Address type
  6. E-mail address

In the calls to IAddrBook::CreateOneOff and IMAPISupport::CreateOneOff, clients and transport providers can set a flag that indicates whether or not the recipient represented by the one-off address can process formatted text or embedded OLE objects. To indicate that a recipient can handle formatted text and OLE objects, clients and transport providers set the MAPI_SEND_NO_RICH_INFO flag in the ulFlags parameter. MAPI then sets the one-off recipient's PR_SEND_RICH_INFO property to FALSE. When this flag is not set, MAPI sets PR_SEND_RICH_INFO to TRUE unless the one-off address is interpreted as an SMTP address. In this one case, PR_SEND_RICH_INFO defaults to FALSE.


Address Book Identifiers

All address book providers assign entry identifiers using the PR_ENTRYID property to their messaging user and distribution list objects. Client applications use these entry identifiers to open and access the objects to which they are assigned.

The address book makes use of three other types of identifiers to represent objects:

  • One-off entry identifiers
  • One-off template entry identifiers
  • Template identifiers

Because of the variety of entry identifiers and the similarity with which they are named, it is easy to become confused about how each type is used and created.

A one-off entry identifier is an entry identifier that is used to open and access the type of recipient known as a one-off, or custom recipient. One-offs are recipients that do not belong to any of the address book providers in the profile. The entry identifiers assigned to one-offs use a format reserved for one-off recipients. Because one-off entry identifiers are used to open and access objects, they are stored in the PR_ENTRYID property.

One-offs and one-off entry identifiers are created:

  • When users of a client application elect to add a recipient that does not represent any entry in the address book to a message's recipient list.
  • When users of a client application elect to add a recipient that does not represent any entry in the address book to a modifiable address book container.
  • When a transport provider receives a message with an address that cannot be handled by its related address book provider.
  • When a transport provider receives a message with an address that belongs to a gateway.

In the first two situations, the client calls IAddrBook::CreateOneOff to associate a one-off entry identifier with the newly created one-off recipient. In the second two situations, the transport provider calls IMAPISupport::CreateOneOff to associate a one-off entry identifier with the foreign address.

A one-off template entry identifier is a short-term entry identifier that is used to open and access a template for creating one-offs. Address book providers and MAPI supply templates for entering the information that is required to create a recipient of a particular type. Information about these templates, including their entry identifiers, is published in the one-off table. One-off tables are displayed when MAPI calls either the IABLogon::GetOneOffTable method or an address book container's IMAPIProp::OpenProperty method to request the PR_CREATE_TEMPLATES property or when a provider calls IMAPISupport::GetOneOffTable.

To create a new one-off, a user selects one of the templates listed in the one-off table. The client passes the PR_ENTRYID column from the selected row, which is the one-off template entry identifier of the selected template, to IAddrBook::NewEntry in the lpEIDNewEntryTpl parameter. MAPI uses the one-off template entry identifier to display the template and allow the user to enter the information needed to create the recipient.

A template identifier is an entry identifier that some address book providers assign to their recipients in addition to the entry identifier that is kept in the PR_ENTRYID property. Providers set a recipient's PR_TEMPLATEID property to store its template identifier. Some address book providers assign the same value for a recipient's template identifier and entry identifier properties.

Template identifiers are used only by address book providers and by MAPI to bind recipient data in one provider, referred to as the host provider, to code for the recipient in another provider, referred to as the foreign provider. The host provider supplies the storage for the recipient; the foreign provider supplies the logic. The binding process enables a host provider to update the data of a recipient that it stores using the code of a foreign provider.

When the host provider is ready to modify its recipient, it passes the PR_TEMPLATEID property in a call to the IMAPISupport::OpenTemplateID method to initiate the binding process. MAPI continues the process by transferring the template identifier to the appropriate foreign provider through a call to its IABLogon::OpenTemplateID method. The foreign provider returns a pointer to its IMAPIProp implementation for the recipient, which the host provider can use in place of its own implementation.


One-Off Entry Identifiers

One-off entry identifiers are created by MAPI in the IAddrBook::CreateOneOff method and by components that do not have access to the MAPI subsystem, such as gateway components. The one-off entry identifier uses a specific format, defined as follows.

The first field is a special MAPIUID structure that identifies the entry identifier as representing a custom recipient. This MAPIUID structure must be set to the constant MAPI_ONE_OFF_UID. MAPI_ONE_OFF_UID is defined in the header file MAPIDEFS.H.

The version and flags fields are 16-bit words in Intel byte order. The version field must be set to zero. The flags field can be set to the following values:

MAPI_ONE_OFF_NO_RICH_INFO

MAPI_ONE_OFF_UNICODE

The MAPI_ONE_OFF_NO_RICH_INFO flag is set if a recipient should not receive message content in the Transport Neutral Encapsulation Format (TNEF). IAddrBook::CreateOneOff sets this flag when it is passed the MAPI_SEND_NO_RICH_INFO flag.

The MAPI_ONE_OFF_UNICODE flag is set if the display name and e-mail address are Unicode strings. IAddrBook::CreateOneOff sets this flag when it is passed the MAPI_UNICODE flag. When the MAPI_UNICODE flag is not passed to CreateOneOff, MAPI assumes that the display name and e-mail address strings are in the workstation's current ANSI character set. ANSI strings generally do not work well in messages that are sent between platforms using different character sets because the code page is not encoded in the entry identifier. To protect against this potential incompatibility, many address types are limited to only those characters that are common across multiple character sets. However, to ensure character set and platform compatibility, clients should use Unicode for the character strings in their messages.

The display name is a null-terminated string that corresponds to the recipient's PR_DISPLAY_NAME property and to the lpszName parameter passed to IAddrBook::CreateOneOff. The character set is Unicode if the MAPI_ONE_OFF_UNICODE flag is set and ANSI if it is clear.

The address type is a null-terminated string that corresponds to the recipient's PR_ADDRTYPE property and to the lpszAdrType parameter passed to IAddrBook::CreateOneOff.

The e-mail address is a null-terminated string that corresponds to the recipient's PR_EMAIL_ADDRESS property and to the lpszAddress parameter passed to IAddrBook::CreateOneOff.

Note There is no padding in one-off entry identifier structures; the bytes are packed exactly as indicated above and the entry identifier length should not include any bytes beyond the terminating null character of the e-mail address.

Clients and address book providers that manually construct one-off entry identifiers might also need to generate values for the PR_RECORD_KEY and PR_SEARCH_KEY properties. The record key is identical to the entry identifier. The search key should be formed by concatenating the following fields in the following order:

  1. The address type, converted to uppercase characters
  2. A colon (:)
  3. The e-mail address, converted to uppercase characters
  4. A terminating null character

No character set conversion must be done when generating the search key.


Status Objects

Status objects report information about a MAPI resource: a service provider, the MAPI subsystem, the MAPI spooler, or the address book.

There is a status object supplying information about each individual service provider in the current profile. MAPI is responsible for implementing status objects for the subsystem, the MAPI spooler, and the address book. The subsystem status object supplies global information. The MAPI spooler status object supplies information about the status of all transport providers currently open. The status object for the integrated address book supplies the status of all address book providers currently operating.

Every status object is included in the status table, a table maintained by MAPI that provides clients with all of the status information for the session. Clients can access a particular status object either through the table or, for a service provider, through its logon object. For example, to access an address book provider's status object, a client can call IABLogon::OpenStatusEntry.

Clients can use status objects to:

  • Learn about the state of a session.
  • Monitor a service provider.
  • Control message transmission.
  • View or change a resource's configuration and status.

Every status object implements the IMAPIStatus interface. However, not every status object fully supports every IMAPIStatus method. Because there is variation in the methods that are supported by a status object, clients need to learn about a particular status object before they can use it. Status objects are required to publish information about their features in the following three properties:

PR_RESOURCE_METHODS

PR_RESOURCE_TYPE

PR_RESOURCE FLAGS

For more information about the status table, see Status Table. For more information about implementing a status object, see Implementing a Status Object. For more information about using a status object, see Using the Status Table and Status Objects.


Profiles

A profile stores information about service providers and message services that are installed on a workstation. For every session, a client at logon time selects one profile that describes the providers and services to be used. A client can choose from a collection of profiles and, if desired, establish one as the default. The default profile is the profile that is selected automatically when a client starts a session and has not explicitly specified a profile.

Profiles are divided into sections and it is these sections that clients and service providers access to display profile properties to users or to make configuration changes. A profile section is a MAPI object that implements the IProfSect interface, an interface that derives from IMAPIProp and has no additional methods. Its purpose is solely to manipulate the properties of a profile section. To retrieve an IProfSect pointer to a particular profile section, clients and service providers call the following methods:

Clients can call: | IMAPISession::OpenProfileSection
Service providers can call: | IMAPISupport::OpenProfileSection
Either clients or providers can call: | IProviderAdmin::OpenProfileSection

Profiles are organized hierarchically much like the MAPISVC.INF file. At the top of the hierarchy, there are profile sections that contain information relevant to the profile. The middle level includes sections that contain information about a particular message service and the lower level includes sections that contain information about one of the service providers in a message service.

Every profile has several required properties that are stored in one or more of the sections of the profile. For example, every profile has the PR_PROFILE_NAME and PR_SEARCH_KEY properties. A profile's search key is set to the value defined in MAPIGUID.H as MUID_PROFILE_INSTANCE and is always guaranteed to be unique among all profiles. Whereas it is possible for two profiles to have the same name, it is not possible for two profiles to have the same search key. Search keys should be treated as binary data rather than data of any particular type.

Message store providers are required to include their message stores' PR_DISPLAY_NAME property in the profile sections for the profile and for the message store provider and keep these entries synchronized. When a message store is created, the provider sets PR_DISPLAY_NAME based on the value stored in these profile sections.

There are two major differences between profile sections and other objects that inherit from IMAPIProp:

  • Profile sections do not support transactions.
  • Profile sections do not support named properties, returning MAPI_E_NO_SUPPORT from their IMAPIProp::GetIDsFromNames and IMAPIProp::GetNamesFromIDs implementations.

Because profile sections do not support transactions, any changes made with calls to IMAPIProp::CopyProps, CopyTo, or SetProps immediately take effect. Clients and service providers can call a profile section's IMAPIProp::SaveChanges method and it will succeed, but it has no affect on the profile section data. Having changes occur immediately can affect how service providers implement the property sheets that clients use to display profile properties to users. Service providers that want users to be able to postpone or undo changes must implement their property sheets with copies of profile sections rather than the real sections. With copies, users can make changes and later cancel those changes, leaving the original profile sections untouched.

The order in which information appears in a profile affects how MAPI configures resources and makes assignments in a session. The following assignments are affected by profile order:

  • Default message store
  • Personal address book
  • Default message store search path
  • Default address book search path
  • Transport provider order

MAPI sets the default message store to be the first message store in the profile that has the STATUS_DEFAULT_STORE flag set in its PR_RESOURCE_FLAGS property, indicating that it is capable of being the default store. Clients can override this setting by calling IMAPISession::SetDefaultStore.

MAPI sets the personal address book (PAB) to be the first container that has the AB_MODIFIABLE and AB_RECIPIENTS flags set in its PR_CONTAINER_FLAGS property, indicating that it can store messaging users and distribution lists. Clients can override this setting by calling IAddrBook::SetPAB.

After assigning the PAB, MAPI sets the default address book directory to the first container that has not been assigned as the PAB and has the AB_RECIPIENTS flag set in its PR_CONTAINER_FLAGS property. If the PAB is the only address book container in the profile that is able to hold recipients, then it is assigned as the default directory. Clients can set this directory explicitly by calling IAddrBook::SetDefaultDir.

MAPI assigns the default search path for the address book to be the PAB followed by each directory that has these property settings:

  • PR_DISPLAY_TYPE set to DT_GLOBAL.
  • PR_CONTAINER_FLAGS set to AB_RECIPIENTS.
  • PR_CONTAINER_FLAGS not set to AB_NOT_DEFAULT.

If there are no containers of type DT_GLOBAL, MAPI assigns the default path to be the PAB and the default directory. Clients can set the default path by calling IAddrBook::SetSearchPath.

MAPI creates a transport order for handling outgoing and incoming messages. When more than one transport provider has registered for a message of a particular type, MAPI uses this order to determine which provider should handle the message. MAPI sets the transport order to be the order in which the transport providers were added to the profile with one exception. The transports that set the STATUS_XP_PREFER_LAST flag in their PR_RESOURCE_FLAGS property are placed last in the order. Clients can set the transport order by calling IMsgServiceAdmin::MsgServiceTransportOrder.

These guidelines for ordering service providers and message services might sometimes conflict. If there is a conflict, include C or C++ code to resolve the conflict. You can use the Delivery and Addressing pages of the Mail and Fax Control Panel applet to inspect a profile that you have created to determine if the providers have been configured as expected.


Primary Identity

Most MAPI sessions have a particular service provider that supplies the primary identity for the session. Typically, it is an address book provider, which supplies identity through one of its messaging user objects or distribution lists. In fact, MAPI recommends that message services that include an address book provider use one of its objects for the primary identity. When a service provider that belongs to a message service supplies the primary identity, all of the other service providers in the message service share this identity.

The MAPISVC.INF configuration file has entries relating to identity at both the message service and service provider level. Message service sections must include an entry that states whether or not the service can supply the primary identity; service provider sections include a similar entry only when the provider can supply an identity.

The following table lists the entries that appear in the message service and service provider sections in the MAPISVC.INF file.

Primary identity supplier PR_RESOURCE_FLAGS setting
Message service
SERVICE_PRIMARY_IDENTITY
Not the message service
SERVICE_NO_PRIMARY_IDENTITY
Service provider
STATUS_PRIMARY_IDENTITY

Although multiple message services can declare their ability to provide a session's primary identity, only one message service is selected to do so. This selection can occur:

  • When a profile is created.
  • When a client calls IMsgServiceAdmin::SetPrimaryIdentity to explicitly establish a particular message service as the provider of the session identity.

When a profile is created, MAPI designates the first message service to be configured that includes a provider with the STATUS_PRIMARY_IDENTITY flag set in its PR_RESOURCE_FLAGS property to supply the primary identity. Within the designated message service, the first provider to be configured with this resource flag set is chosen to provide the identity for the service. The STATUS_PRIMARY_IDENTITY flag is cleared for all other providers in the designated service and other message services in the profile. If at any time the provider supplying primary identity is removed from the profile, MAPI assigns the role to the next provider to be configured that can supply identity. This is determined by the appearance of the PR_RESOURCE_FLAGS=STATUS_PRIMARY_IDENTITY entry in the provider's section in MAPISRV.INF.

When a client calls a message service's IMsgServiceAdmin::SetPrimaryIdentity method, it specifies the MAPIUID for a service provider within the target service. The service provider represented by the MAPIUID is assigned to supply the primary identity for the message service and for the session, and all of the other providers in the service will share this identity.

Every provider in the message service responsible for supplying the primary identity updates its row in the status table to include the following properties.

Primary identity property | Set to
PR_IDENTITY_DISPLAY | Display name of the object supplying the primary identity.
PR_IDENTITY_SEARCH_KEY | Search key for the object supplying the primary identity.
PR_IDENTITY_ENTRYID | Entry identifier for the object supplying the primary identity.

To retrieve the entry identifier for the object supplying the primary identity
  • Call the IMAPISession::QueryIdentity method.

    QueryIdentity searches the status table for the row that contains the value STATUS_PRIMARY_IDENTITY in its PR_RESOURCE_FLAGS column and returns the corresponding PR_IDENTITY_ENTRYID as the entry identifier for the primary identity.


Managing Memory

Knowing how and when to allocate and free memory is an important part of programming with MAPI. MAPI provides both functions and macros that your client or service provider can use to manage memory in a consistent way. The three functions are:

MAPIAllocateBuffer

MAPIAllocateMore

MAPIFreeBuffer

When clients and service providers use these functions, the issue of who "owns" — that is, knows how to release — a particular block of memory is eliminated. A client calling a service provider method need not pass a buffer large enough to hold a return value of any size. The service provider can simply allocate the appropriate amount of memory using MAPIAllocateBuffer and, if necessary, MAPIAllocateMore, and the client can later release it at will using MAPIFreeBuffer, independent of the service provider. For more information about these functions, see Memory Management Functions.

The memory macros are used to allocate structures or arrays of structures of a specific size. Clients and service providers should use these macros rather than allocate the memory manually. For example, if a client needs to perform name resolution processing on a recipient list with three entries, the SizedADRLIST macro can be used to create an ADRLIST structure to pass to IAddrBook::ResolveName with the correct number of ADRENTRY members. All of the memory macros are defined in the MAPIDEFS.H header file. These macros are:

SizedADRLIST | SizedDtblPage
SizedDtblButton | SizedENTRYID
SizedDtblCheckBox | SizedSPropProblemArray
SizedDtblComboBox | SizedSPropTagArray
SizedDtblEdit | SizedSRowSet
SizedDtblGroupBox | SizedSSortOrderSet
SizedDtblLabel |

MAPI also supports the use of the OLE interface IMalloc for memory management. Service providers are given an IMalloc interface pointer by MAPI at initialization time and can also retrieve one through the MAPIGetDefaultMalloc function. The main advantage to using the IMalloc methods for managing memory over the MAPI functions is that with the OLE methods it is possible to reallocate an existing buffer. The MAPI memory functions do not support reallocation.


Managing Memory for ADRLIST and SRowSet Structures

The requirement to allocate all memory for a buffer whenever possible with a single MAPIAllocateBuffer call does not apply when using the address list, or ADRLIST, and row set, or SRowSet, structures. These two structures are exceptions to the standard rules for allocating and releasing memory. They contain multiple levels of structures and are designed to enable individual members to be added or removed. Therefore, each property must be a separate allocation. Where most structures are freed with one call to MAPIFreeBuffer, each individual entry in an ADRLIST or SRowSet structure must be freed with its own call to MAPIFreeBuffer or a single call to either FreeProws or FreePadrlist. FreeProws and FreePadrlist are functions provided by MAPI for simplifying the freeing of these data structures. FreePadrlist frees the memory for the ADRLIST structure plus all associated memory for the structure members; FreeProws does the same for the SRowSet structure.

The following diagram shows the layout of an ADRLIST data structure, indicating the separate memory allocations required. The gray boxes show memory that can be allocated and released with one call.


Allocating and Freeing Memory

In addition to specifying how to allocate and free memory, MAPI defines a model for knowing when memory passed between public interface method and API function calls should be freed. The model applies only to memory allocated for parameters that are not pointers to interfaces, such as strings and pointers to structures. Interface pointers use the reference counting mechanism implemented through IUnknown. When allocating and freeing non-MAPI related memory internally within a client application or service provider, use whatever mechanism makes sense.

The model defines parameters as one of three types. They can be input parameters, set by the caller with information to be used by the called function or method, output parameters, set by the called function or method and returned to the caller, or input-output parameters, a combination of the two types. Output parameters are frequently pointers to data or pointers to pointers to data. Although the called function is responsible for allocating the data for output parameters, the caller allocates the memory for the pointer.

The rules for allocating and releasing memory for these types of parameters are explained in the following table.

Type | Memory allocation | Memory release
Input | Caller is responsible and can use any mechanism. | Caller is responsible and can use any mechanism.
Output | Called function is responsible and must use MAPIAllocateBuffer. | Caller is responsible and must use MAPIFreeBuffer.
Input-output | Caller is responsible for the initial allocation and called function can reallocate if necessary using MAPIAllocateBuffer. | Called function is responsible for initial freeing if reallocation is necessary. Caller must free the final return value.

During failure conditions, implementers of interface methods need to pay attention to output and input-output parameters since the caller generally has no way to clean them up. If an error is returned, then each output or input-output parameter must either be left at the value initialized by the caller or set to a value that can be cleaned up without any action on the part of the caller. For example, an output pointer-parameter of void ** ppv must be left as it was on input or can be set to NULL (*ppv = NULL).


Error Handling

Success, warning, and error values are returned using a 32-bit number known as a result handle, or HRESULT . An HRESULT is really not a handle to anything; it is merely a 32-bit value with several fields encoded in the value. A zero result indicates success and a nonzero result indicates failure.

HRESULT values work differently depending on the platform your client or service provider is using. On 16-bit platforms, an HRESULT is generated from a 32-bit value known as a status code, or SCODE. On 32-bit platforms, an HRESULT is the same as an SCODE; they are synonymous data types. MAPI on 32-bit platforms works solely with HRESULT values.

SCODEs on 16-bit platforms are divided into four fields: a severity code, a context field, a facility field, and an error code. The format of an SCODE on a 16-bit platform is shown below; the numbers indicate bit positions.

HRESULTs on 32-bit platforms have the following format.

The severity code in the 16-bit SCODE and the high order bit in the HRESULT indicate whether the return value represents success or failure. If set to zero, the value indicates success. If set to 1, it indicates failure.

In the 16-bit version of the SCODE, the context field is reserved as are the R, C, N, and r bits in the HRESULT.

The facility field in both versions indicates the area of responsibility for the error. There are several facilities, but the vast majority of MAPI errors use FACILITY_ITF to represent interface errors. The most common facilities that are currently used are: FACILITY_NULL, FACILITY_ITF, FACILITY_DISPATCH, FACILITY_RPC, and FACILITY_STORAGE. If new facilities are necessary, Microsoft allocates them because they need to be unique. The following table describes the various facility fields.

Facility | Description
FACILITY_NULL | For broadly applicable common status codes such as S_OK or E_OUTOF_MEMORY; the value is zero.
FACILITY_ITF | For most status codes returned from interface methods; the value is defined by the interface. That is, two SCODE or HRESULT values with exactly the same 32-bit value returned from two different interfaces might have different meanings.
FACILITY_DISPATCH | For late binding IDispatch interface errors.
FACILITY_RPC | For status codes returned from remote procedure calls.
FACILITY_STORAGE | For status codes returned from IStorage or IStream method calls relating to structured storage. Status codes with code (lower 16 bits) values in the range of MS-DOS error codes (that is, less than 256) have the same meaning as the corresponding MS-DOS errors.

The code field is a unique number that is assigned to represent the error or warning.


Return Value Naming Convention

The MAPICODE.H header file contains many of the values that a client or service provider might return from an interface method implementation or might see returned from a call. These values are SCODE values rather than HRESULT values. The OLE SCODE value S_OK is used to represent success in MAPI calls.

The codes to represent warning and failure conditions follow a different naming convention that begins with the prefix MAPI, an underscore, and either a W or an E to indicate the type of code. The rest of the code is a short character string to describe the condition. Each word in the string is separated by an underscore. For example, the error value MAPI_E_TOO_COMPLEX indicates that the implementation could not handle whatever was being requested in the call. The warning value MAPI_W_PARTIAL_COMPLETION indicates that the call succeeded, but that there were problems. Only part of the operation was completed successfully.


Using Macros for Error Handling

There are several macros for making it easier to work with SCODE values on 16-bit platforms and HRESULT values on both 16- and 32-bit platforms. Some of the macros and functions below provide conversion between the two datatypes and can be used in client and service provider code that:

  • Runs only on 16-bit platforms.
  • Runs on both 16-bit and 32-bit platforms.
  • Is 16-bit code being ported to 32-bit platforms.

For 32-bit environments, these datatype conversion macros exist to provide compatibility and to ease the porting effort.

There are two sets of macros that test for failure or success: HR_SUCCEEDED and HR_FAILED and SUCCEEDED and FAILED.

On 32-bit platforms, because SUCCEEDED is the same as HR_SUCCEEDED and FAILED is the same as HR_FAILED, developers that want to write cross-platform clients or service providers are the only ones that need to distinguish between an HRESULT and an SCODE.

In this case, use the ResultFromScode macro to set the HRESULT variable to the corresponding HRESULT value for S_OK.

Warning The macro SCODE_FACILITY retrieves twelve bits from the SCODE in its Win16 implementation when it should only retrieve four. This can cause false negative results to occur when comparing the facility retrieved from a particular SCODE against predefined facility values. Programmers writing cross-platform code need to be aware of this problem.

Commonly used macros are briefly described in the following table.

Macro | Description
GetScode | Converts an HRESULT into an SCODE.
ResultFromScode | Converts an SCODE into an HRESULT.
MAKE_SCODE | Constructs an SCODE from its components.
MAKE_HRESULT | Constructs an HRESULT from its components.
HR_SUCCEEDED | Tests an HRESULT for a success or warning condition.
HR_FAILED | Tests an HRESULT for an error condition.
HRESULT_CODE | Extracts the error code part of the HRESULT.
HRESULT_FACILITY | Extracts the facility from the HRESULT.
HRESULT_SEVERITY | Extracts the severity bit from the SEVERITY.
SCODE_CODE | Extracts the error code part of the SCODE.
SCODE_FACILITY | Extracts the facility from the SCODE.
SCODE_SEVERITY | Extracts the severity field from the SCODE.
SUCCEEDED | Tests an SCODE for a success or warning condition.
FAILED | Tests an SCODE for an error condition.


How Return Values are Documented

The reference entries in the MAPI Programmer's Reference document only those return values that require some handling by client applications or service providers. Return values that indicate common error conditions and can be deduced by checking for failure are not included in the documentation. For example, many interface methods can return MAPI_E_INVALID_PARAMETER if a caller specifies the wrong value for an input parameter. This value is typically not listed in the set of expected return values because there is no need to look specifically for MAPI_E_INVALID_PARAMETER and no need to process it differently from any other error. On the other hand, some service providers do not support event notification and will return MAPI_E_NO_SUPPORT to the Advise method made by clients through IMAPISession. Because clients need to explicitly check for this value and provide code for handling the condition that it represents should it occur, MAPI_E_NO_SUPPORT is included in the list of return values for IMAPISession::Advise.

The following table describes error values that are commonly returned from methods and functions and require explicit handling on the part of a client or service provider. These values fall into four categories: values that indicate invalid input data, values that indicate resource problems, values that indicate character set incompatibility, and values that indicate failure of an unknown origin.

Return value | Description
MAPI_E_INVALID_PARAMETER | One or more of the parameters passed into the method or functions were not valid.
MAPI_E_UNKNOWN_FLAGS | One or more values for a flags parameter were not valid.
MAPI_E_DISK_ERROR | There was a problem writing to or reading from disk.
MAPI_E_NOT_ENOUGH_DISK | Not enough disk space was available to complete the operation.
MAPI_E_NOT_ENOUGH_MEMORY | Not enough memory was available to complete the operation.
MAPI_E_NOT_ENOUGH_RESOURCES | Not enough system resources were available to complete the operation.
MAPI_E_BAD_CHARWIDTH | An incompatibility exists in the character sets supported by the caller and the implementation.
MAPI_E_CALL_FAILED | An error of unexpected or unknown origin occurred.

The constants that represent MAPI return values are listed in the MAPICODE.H header file. Some of the constants map to Win32 errors; the mapping of these constants to numeric values can be found in the Win32 header file, WINERROR.H.

Errors regarding invalid data passed in by a caller can be determined through either the parameter validation API functions provided by MAPI or a set of macros. For more information on how to use the MAPI parameter validation model in your programs, see Validating Parameters to Interface Methods.

Character set incompatibility arises when either of the following situations occurs:

  • A client or service provider sets the MAPI_UNICODE flag on a method or function call and the implementation does not support Unicode. Setting MAPI_UNICODE indicates that character strings passed in as input are Unicode strings and that character strings passed back as output are expected to be Unicode strings.
  • A client or service provider does not set the MAPI_UNICODE flag on a method or function call and the implementation only supports Unicode.


Strategies for Error Handling

Because interface methods are virtual, it is not possible to know, as a caller, the full set of values that can be returned from any one call. One implementation of a method might return five values; another might return eight. The reference entries in the MAPI Programmer's Reference list a few values that can be returned for each method; these are the values that your client or service provider can check for and handle because they have special meanings. Other values can be returned, but since they are not meaningful, special code to handle those is not necessary. A simple check for success or failure is adequate.

A few of the interface methods return warnings. If a method that your client or service provider calls can return a warning, use the HR_FAILED macro to test the return value rather than a check for zero or nonzero. Warnings, although nonzero, differ from error codes in that they do not have the high bit set. If your client or service provider does not use the macro, it is likely that a warning might be mistaken for a failure.

Although most interface methods and functions return HRESULT values, some functions, primarily those defined for Simple MAPI, return unsigned long values. Also, some methods used in the MAPI environment come from OLE and return OLE error values rather than MAPI error values. Keep in mind the following guidelines when making calls:

  • Never rely on or use the return values from IUnknown::AddRef or IUnknown::Release. These return values are for diagnostic purposes only.
  • IUnknown::QueryInterface always returns generic OLE errors where the facility is FACILITY_NULL or FACILITY_RPC, rather than MAPI errors.
  • All other interface methods return MAPI interface errors with a facility of FACILITY_ITF, or FACILITY_RPC or FACILITY_NULL errors.
  • Simple MAPI calls return Simple MAPI errors rather than SCODE or HRESULT values.
  • CMC calls have their own defined set of error codes. CMC codes are unsigned long values.
  • No MAPI call ever returns a Simple MAPI error value.

If your service provider works with clients that use both the Simple MAPI and MAPI client interfaces, be aware that although the underlying values for some of the errors are different, the constants defined for them are quite similar. For example, when a call is made to an unsupported feature in Simple MAPI, the error MAPI_E_NOT_SUPPORTED is returned. When the same type of call is made to a MAPI method, one of four possible errors can be returned:

MAPI_E_NO_SUPPORT

MAPI_E_INTERFACE_NOT_SUPPORTED

MAPI_E_INVALID_PARAMETER

MAPI_E_VERSION.

For this reason, avoid including the Simple MAPI header file, MAPI.H, in your client or service provider. The table below points out these similarities and differences.

Simple MAPI return value | MAPI return value
MAPI_E_NOT_SUPPORTED | MAPI_E_NO_SUPPORT MAPI_E_INTERFACE_NOT_SUPPORTED MAPI_E_INVALID_PARAMETER MAPI_E_VERSION
MAPI_E_DISK_FULL | MAPI_E_NOT_ENOUGH_DISK
MAPI_E_NETWORK_FAILURE | MAPI_E_NETWORK_ERROR
MAPI_E_USER_ABORT | MAPI_E_USER_CANCEL
MAPI_E_ACCESS_DENIED | MAPI_E_NO_ACCESS
MAPI_E_AMBIGUOUS_RECIPIENT | MAPI_E_AMBIGUOUS_RECIP


Using Extended Errors

Implementers of interface methods can choose to simply return success (S_OK) and failure (MAPI_E_CALL_FAILED) or differentiate between error conditions, returning as many error values as make sense for the situation. Most situations can use one of the error values defined by MAPI in the MAPICODE.H header file. However, for situations that are not covered by a predefined value, the value MAPI_E_EXTENDED_ERROR can be used. MAPI_E_EXTENDED_ERROR indicates to the caller that more information about the error is available. The caller retrieves the additional information by calling the GetLastError method on the same object that returned MAPI_E_EXTENDED_ERROR.

GetLastError can be called to retrieve information about any error code, not only MAPI_E_EXTENDED_ERROR. Many MAPI objects implement interfaces that include the GetLastError method. GetLastError returns a single MAPIERROR structure that, in theory, includes a concatenation of all the errors generated by the previous method call. As a caller, it is wise not to depend on having this extra error information available because object implementers are not required to provide it. However, it is strongly recommended that whenever implementers return MAPI_E_EXTENDED_ERROR, they make it possible for callers to retrieve a MAPIERROR structure with useful information about the error.

Because GetLastError is also an API function that is part of the Platform SDK, it can be easy to forget that in MAPI, GetLastError is an interface method and can only be called on MAPI objects. Another easy mistake to make is calling GetLastError on the wrong object. GetLastError must be called on the object that generated the error. For example, if your client makes a session call, and MAPI forwards the call to a service provider to do the work, your client should not call GetLastError on the service provider object. IMAPISession::GetLastError is the correct call; GetLastError should be invoked on the session object.


Deferring Errors

Some interface methods accept the MAPI_DEFERRED_ERRORS flag as an input parameter. When this flag is set, the method does not have to return immediately with a value; it can let the caller know the result of the call at some later time.

Deferring errors helps service providers in their implementation of complex methods, making processing faster. Rather than handling many requests and returning a value for each, deferring errors allows the calls to be bundled within the service provider. Processing many requests at once cuts down on network traffic, thereby improving performance. Deferring errors is especially useful in calls to delete or copy properties, which can be very time-consuming operations.

When a client makes a call without setting the MAPI_DEFERRED_ERRORS flag that can only be handled in a deferred manner, service providers can either defer the errors regardless or return MAPI_E_TOO_COMPLEX. Most clients should defer errors as a preferable strategy to failing the call.

Setting the MAPI_DEFERRED_ERRORS flag changes a client's error handling implementation in that the returned information can be delivered at any time rather than at a planned time. It is possible for an error to be returned when it is too late to do anything about it or after data about the original request is no longer available. For example, if a client calls IMsgStore::OpenEntry to open a deleted folder with MAPI_DEFERRED_ERRORS set, the client will not know of the problem until an IMAPIProp::GetProps call is made to retrieve one of the folder's properties. GetProps will then return MAPI_E_NOT_FOUND.


Sending Messages with MAPI

Client applications call the IMessage::SubmitMessage method to send a message. SubmitMessage calls IMAPIProp::SaveChanges to save the message before transferring control to either the MAPI spooler or directly to a transport provider. The MAPI spooler receives the message if:

  • The message store provider and transport provider are not tightly coupled.
  • The message requires preprocessing.
  • The tightly coupled message store and transport cannot handle all of the recipients to whom the message is addressed.

A tightly coupled message store must take into account a message's status before it presents it to the MAPI spooler to be downloaded to a transport provider. There are situations where a message may appear to require the MAPI spooler, but the MAPI spooler should really not be involved.

For example, consider the situation where a user submits a message from the Inbox. The client is using a tightly coupled store and transport. If the tightly coupled message store uses the message's location as the sole criteria for deciding about whether or not to allow the MAPI spooler to handle the message, the MAPI spooler will always receive the message. To avoid this kind of problem, a tightly coupled message store must check the message status in addition to message location. Specifically, the transport provider should not request that the MAPI spooler download any message that is actively submitted.

The message transmission process involves the message store provider, one or more transport providers, and MAPI. The following topics provide detailed information about specific roles in the message transmission process:

For information about a message store provider's role in sending messages, see Sending Messages: Message Store Provider Tasks.

For information about the MAPI spooler's role in sending messages, see Sending Messages: MAPI Spooler Tasks.

For information about a transport provider's role in sending messages, see Sending Messages: Transport Provider Tasks.

For information, from the client perspective, about what to do with a message after it has already been sent, see Processing a Sent Message.


Delegate Access

Delegate access refers to the user's ability to send a message as another user or receive a message for another user. Delegate access is a service provider-independent feature of MAPI that transport providers can support if they choose. However, no provider is required to do so. Delegate access is valuable when it is necessary for a user to send messages as, or filter incoming messages for, another user or when a user must access another user's message store. Before allowing a delegate user to connect to another user's store, the message store provider must verify that the delegate user has the proper authority.

There are two groups of properties that are used to support delegate access:

PR_SENT_REPRESENTING_ADDRTYPE

PR_SENT_REPRESENTING_EMAIL_ADDRESS

PR_SENT_REPRESENTING_ENTRYID

PR_SENT_REPRESENTING_NAME

PR_SENT_REPRESENTING_SEARCH_KEY

PR_RCVD_REPRESENTING_ADDRTYPE

PR_RCVD_REPRESENTING_EMAIL_ADDRESS

PR_RCVD_REPRESENTING_ENTRYID

PR_RCVD_REPRESENTING_NAME

PR_RCVD_REPRESENTING_SEARCH_KEY

On outgoing messages, the PR_SENT_REPRESENTING properties identify the messaging user that should act as the sender. Clients can set these properties as an option. If the PR_SENT_REPRESENTING properties are not set by the time the message reaches a transport provider that supports delegate access, it is the provider's responsibility to set them along with the PR_SENDER properties.

On incoming messages, the PR_RCVD_REPRESENTING properties identify the user that should act as the recipient. Transport providers responsible for delivering delegate messages must set both the PR_RCVD_REPRESENTING and PR_RECEIVED_BY properties. Clients receiving a delegate message should copy the values of the PR_SENT_REPRESENTING properties to the corresponding PR_RCVD_REPRESENTING properties.

For example, suppose John is receiving Sally's messages while Sally is on vacation. The PR_RCVD_REPRESENTING properties identify John as the delegate recipient. When John sends a reply to a message that he has received for Sally, the message's PR_SENDER properties identify John as the sender. Because John is representing Sally, the PR_SENT_REPRESENTING properties identify Sally.

Transport providers handling incoming delegate messages should usually deliver these messages as the messaging user identified by the PR_SENT_REPRESENTING properties rather than as the user identified by the PR_SENDER properties. The exception to this rule is when it is necessary to match access privilege and transport types. In this case, a transport provider can choose a sending identity.

If the PR_SENT_REPRESENTING properties are unavailable for an incoming delegate message, the transport provider handling delivery must set them, using the values of the corresponding PR_SENDER properties. If the PR_SENT_REPRESENTING properties are available but the transport provider does not support delegate access, it can use the PR_SENDER properties for delivery.


Sending Messages with TNEF

Many transport providers automatically send all outgoing messages with the Transport Neutral Encapsulation Format, or TNEF. TNEF is used to transmit the formatted text that many clients and message store providers support in their messages, attachments of various types, and custom properties for custom message classes. Although the default mode for most transport providers is to send outgoing messages with TNEF, some transport providers do not support it. The lack of support for TNEF is not an issue for standard messaging clients that send and receive IPM messages. However, for form-based clients or clients that require custom properties, the use of TNEF is essential. Designers of clients that rely on forms or custom properties must be aware of the capabilities of the transport providers that they use.

Message recipients can control whether or not a transport provider transmits messages with TNEF by setting the PR_SEND_RICH_INFO property. When a recipient's PR_SEND_RICH_INFO property is set to TRUE, a transport provider that supports TNEF transmits it with the message. When the property is set to FALSE, the formatting is discarded. When PR_SEND_RICH_INFO does not exist, it is up to the transport provider to choose a default course of action.

When clients and service providers create a custom recipient, they can affect the value of its PR_SEND_RICH_INFO property by passing the MAPI_SEND_NO_RICH_INFO flag in the ulFlags parameter to the IAddrBook::CreateOneOff or IMAPISupport::CreateOneOff call. Passing MAPI_SEND_NO_RICH_INFO causes MAPI to set the custom recipient's PR_SEND_RICH_INFO property to FALSE; in most cases not passing the flag causes MAPI to set the property to TRUE. The one exception is if the custom recipient's address is interpreted to be an Internet address. In this one situation, MAPI sets PR_SEND_RICH_INFO to FALSE.


Sending Messages: Message Store Provider Tasks

A message store provider gets involved with the message sending process when a client calls the message's IMessage::SubmitMessage method. If multiple messages are to be sent, the message store must send them in the same order that the client used for its SubmitMessage calls.

The message store provider determines whether or not to involve the MAPI spooler. If the message store provider is not tightly coupled, the message requires preprocessing, or the tightly coupled store and transport cannot handle all of the recipients, the MAPI spooler must be involved.

The following procedure describes the tasks required of a message store provider for sending a message.

In IMessage::SubmitMessage, the message store provider
  1. Calls IMAPISupport::PrepareSubmit if the message has the MSGFLAG_RESEND flag set in its PR_MESSAGE_FLAGS property and returns any errors to the client. PrepareSubmit checks the PR_RECIPIENT_TYPE property of each recipient in the message's recipient list.
    • If the MAPI_SUBMITTED flag is set, indicating that the recipient did not receive the original message, PrepareSubmit clears the flag and sets the PR_RESPONSIBILITY property to TRUE.
    • If the MAPI_SUBMITTED flag is not set, indicating that the recipient did receive the original messsage, PrepareSubmit changes the PR_RECIPIENT_TYPE property to MAPI_P1 and sets the PR_RESPONSIBILITY property to TRUE and returns any error generated by PrepareSubmit to the client.
  2. Sets the MSGFLAG_SUBMIT flag in the message's PR_MESSAGE_FLAGS property.
  3. Makes sure that there is a column for PR_RESPONSIBILITY in the recipient table and sets it to FALSE to indicate that no transport has of yet assumed responsibility for transmitting the message.
  4. Sets the date and time of origination in the PR_CLIENT_SUBMIT_TIME property.
  5. Calls IMAPISupport::ExpandRecips to:
    • Expand all personal distribution lists and custom recipients and replace all changed display names with their original names.
    • Remove duplicate names.
    • Check for any required preprocessing, and if preprocessing is required, set the NEEDS_PREPROCESSING flag and the PR_PREPROCESS property, a property reserved for MAPI.
    • Set the NEEDS_SPOOLER flag if the message store is tightly coupled with a transport and it cannot handle all of the recipients.
  6. Performs the following tasks if the NEEDS_PREPROCESSING message flag is set:
    • Puts the message in the outgoing queue with the SUBMITFLAG_PREPROCESS bit set in the PR_SUBMIT_FLAGS property.
    • Notifies the MAPI spooler that the queue has changed.
    • Returns control to the client, and message flow continues in the MAPI spooler. The MAPI spooler performs the following tasks:
1. Locks the message by calling IMsgStore::SetLockState.
2. Performs the needed preprocessing by calling all of the preprocessing functions in the order of registration. Transport providers call IMAPISupport::RegisterPreprocessor to register preprocessing functions.
3. Calls IMessage::SubmitMessage on the open message to indicate to the message store that preprocessing is complete.

Note The following two steps will occur in the client process if there was no preprocessing and will occur when the MAPI spooler calls SubmitMessage if there was preprocessing.

  7. Performs the following tasks if the message store is tightly coupled to a transport and the NEEDS_SPOOLER flag was returned from IMAPISupport::ExpandRecips:
    • Handles any recipients that it can handle.
    • Sets the PR_RESPONSIBILITY property to TRUE for any recipients that it handles.
    • Performs the following tasks if all recipients are known to this tightly coupled store and transport:
1. Calls IMAPISupport::CompleteMsg if the message was preprocessed or the message store provider wants the MAPI spooler to complete message processing which is recommended so that messaging hooks can be invoked. Message flow continues with the MAPI spooler as described in the following procedure.
2. Performs the following tasks if the message was not preprocessed or the message store provider does not want the MAPI spooler to complete message processing:
· Copies the message to the folder identified by the entry identifier in the PR_SENTMAIL_ENTRYID property, if set.
· Deletes the message if the PR_DELETE_AFTER_SUBMIT property has been set to TRUE.
· Unlocks the message if it is locked.
· Returns to the client. Message flow is complete.

  8. Performs the following tasks if the message store is not tightly coupled to a transport, not all of the recipients were known to the message store, or the NEEDS_SPOOLER flag is set:
    • Puts the message in the outgoing queue without setting the SUBMITFLAG_PREPROCESS bit in the PR_SUBMIT_FLAGS property.
    • Notifies the MAPI spooler that the outgoing queue has changed by generating a table notification.
    • Returns to the client, and message flow continues with a set of tasks performed by the MAPI spooler.

When a message is to be handled by the MAPI spooler, the message store provider sets the message's PR_SUBMIT_FLAGS property to SUBMITFLAG_LOCKED. The SUBMITFLAG_LOCKED flag indicates that the MAPI spooler has locked the message for its exclusive use. The other value for PR_SUBMIT_FLAGS, SUBMITFLAG_PREPROCESS, is set when the message requires preprocessing by one or more preprocessor functions registered by a transport provider.


Sending Messages: MAPI Spooler Tasks

The MAPI spooler is involved in the message transmission process when the message store is not tightly coupled with a transport provider, when the tightly coupled store and transport cannot handle a recipient, and when the message requires preprocessing.

After any necessary preprocessing, the MAPI spooler
  1. Locks the message by using the IMsgStore::SetLockState method if the message is not locked.
  2. Has the transport provider send the message to all recipients that have their PR_RESPONSIBILITY property set to FALSE.
  3. Calls the appropriate function (RemovePreprocessInfo) for cleaning up any additional information that was added to the message for use during preprocessing if the PR_PREPROCESS property has been set. This function is specified when the transport provider registers its preprocessor function.
  4. Calls IMsgStore::FinishedMsg. In FinishedMsg, the message store provider:
    • Unlocks the message.
    • Calls the IMAPISupport::DoSentMail method to perform outbound hook processing if a messaging hook provider exists. It then copies the message to the folder identified by the entry identifier in the PR_SENTMAIL_ENTRYID property, if not superseded by a messaging hook provider's sent message processing. Finally, it deletes the message if the PR_DELETE_AFTER_SUBMIT property has been set to TRUE.


Sending Messages: Transport Provider Tasks

To transmit a message, transport providers
  • Set the message's PR_RESPONSIBILITY property to TRUE after the transport provider has either sent the message or attempted to send the message. If an attempt to send a message fails, transport providers should call IMAPISupport::StatusRecips to generate a nondelivery report. If the message is sent successfully and the PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED property is set to TRUE, create an ADRLIST structure containing the successful recipients, setting the PR_DELIVER_TIME property for each, and call StatusRecips to generate a delivery report.

    For more information about creating delivery and nondelivery reports, see the following topics:

    Report Messages

    Required Report Message Properties

    Optional Report Message Properties

    Sending Message Delivery Reports with Transport Providers

  • Set the message's PR_SENDER group of properties to the identity of the user that has logged on. This group includes:

    PR_SENDER_ENTRYID

    PR_SENDER_NAME

    PR_SENDER_SEARCH_KEY

    PR_SENDER_ADDRTYPE

    PR_SENDER_EMAIL_ADDRESS

  • Set the message's PR_SENT_REPRESENTING properties, if possible, to either the identity of the user that has logged on or to a valid delegate identity. The PR_SENT_REPRESENTING properties are used to implement the sending of messages by one user on behalf of another user. Transport providers that do not support these properties should ignore them on outbound messages.
  • Set the message's PR_CLIENT_SUBMIT_TIME property to indicate when the client called IMessage::SubmitMessage.
  • Set the message's PR_PROVIDER_SUBMIT_TIME property to indicate the date and time that the message store provider marked the message as having been sent.

When a message is sent to a variety of recipients with several messaging systems, each transmitted copy will have a different sender identity.

The transport provider or tightly coupled message store and transport is also responsible for setting originator and reply-to information. Originator information is stored in the PR_ORIGINATOR properties and reply-to information is stored in the PR_REPLY properties. The client can set these properties; however, the transport provider is allowed to ignore and overwrite the client's settings.


Sending Across Messaging Domains

A messaging domain represents one or more messaging systems that share a common address format. Communication across multiple messaging domains involves translating a message sent in the format of the original messaging domain into the format of the destination messaging domain. Because not all address formats are compatible, a gateway is needed to translate the addressing information from the source format into the destination format. To ensure validity across messaging domains, client applications store important addressing information in MAPI properties. In addition, gateways perform the translation, examining the properties known to need translation and changing them to a format that the destination messaging domain can use.

Previously, MAPI allowed this addressing information to be associated with only the users who comprise a message's current recipient list. The properties describing each member of the recipient list underwent the required translation by the gateway to ensure validity across messaging domains. However, some applications require that their messages include addressing information about users that perhaps were recipients in the past, will be recipients in the future, or will never be recipients. For example, routing applications, which send messages in a specified order to a group of users, embed addressing information about these users in the messages. The embedded information typically includes the address and address type of the future recipients, and perhaps also their roles and positions in the routing order, their names, and one or more binary identifiers per recipient.

To enable messages to include information about these nonrecipient users, MAPI now includes a strategy for ensuring that this nonrecipient information is also translated correctly across messaging domains. This strategy is based on the concept of gateway-mappable properties.


Gateway Mappable Properties

Gateway-mappable properties are properties that may require translation when sent from one messaging domain to another. MAPI's gateway-mappable properties allow messages to include information that requires a gateway to ensure the destination messaging system uses it properly. Although gateway developers are not required to provide this translation capability, they should consider gateway-mappable properties as an opportunity to handle message content even better.

MAPI specifies five types of gateway-mappable properties:

  • Display name
  • E-mail address
  • E-mail type
  • Entry identifier
  • Search key

This is the set of addressing properties that are associated with recipients, senders, report recipients, and delegated senders and recipients. To help your client define these properties so that a gateway handles them specially, MAPI specifies a naming convention using named properties and property sets. Five property sets exist to hold named properties, the addressing properties that require mapping. There is one property set for each type of mappable property. The property sets that will hold these named addressing properties are as follows.

Property set | Description
PS_ROUTING_DISPLAY_NAME | Contains string properties used as display names.
PS_ROUTING_EMAIL_ADDRESSES | Contains string properties used as e-mail addresses.
PS_ROUTING_ADDRTYPE | Contains string properties used as e-mail address types.
PS_ROUTING_ENTRYID | Contains binary properties used as long-term entry identifiers.
PS_ROUTING_SEARCH_KEY | Contains binary properties used as search keys.


Client Naming Responsibilities

Clients must follow a naming convention for their properties that need to be translated by a gateway. All properties to be translated should be created as named properties in one of the five property sets designated to hold mappable properties:

PS_ROUTING_EMAIL_ADDRESSES

PS_ROUTING_ADDRTYPE

PS_ROUTING_DISPLAY_NAME

PS_ROUTING_ENTRYID

PS_ROUTING_SEARCH_KEY

Addressing properties that relate to the same user must be given the same name. Gateways rely on this naming convention, which enables them to match an address with its correct address type. For address parsing, the mapping between address and address type must be accurate.

MAPI named properties are represented with the MAPINAMEID data structure, which specifies that the property name can be either a Unicode string or a 32-bit integer. Integer naming is recommended for groups of addresses because it is a straightforward way to differentiate between sets of mappable properties, and it can easily serve as an index to the user. The alternative to using integers is to assign one string as the name for all five of a user's mappable properties. If only one user requires mapping, assigning a string is acceptable. However, when there are multiple users, it is better to use integer naming. The name, whether it be numeric or string-based, should be stored in either a message class-specific property or in a property belonging to a property set that is defined by the client application.

Note Avoid translating integer names to strings, such as "route_recipient_1" and "route_recipient_2." This effort is unnecessary.

To illustrate how this naming convention works, consider a routing application that sends a message to each member of a four-person team. When one member receives the message, he or she must respond to it before it can be sent along with the compiled responses to the next member. The original message contains a recipient list with one entry: the first member of the team. Embedded within the message are the gateway-mappable properties for the other three team members. Each member has five core user properties residing in the gateway-mappable property sets, assigned a unique number as a name.

The following table illustrates the settings for each set of gateway-mappable properties stored for the three remaining team members to whom the message is routed when the first team member is finished with it.

Property Set | Second Team Member | Third Team Member | Fourth Team Member
PS_ROUTING_EMAIL_ADDRESSES | Address = 0 | Address = 1 | Address = 2
PS_ROUTING_ADDRTYPE | Address type = 0 | Address type = 1 | Address type = 2
PS_ROUTING_DISPLAY_NAME | Display name = 0 | Display name = 1 | Display name = 2
PS_ROUTING_ENTRYID | Entry identifier = 0 | Entry identifier = 1 | Entry identifier = 2
PS_ROUTING_SEARCH_KEY | Search key = 0 | Search key = 1 | Search key = 2

Clients that use mappable search keys as references to other message properties must recognize that the other message properties will not be translated unless they are placed in one of these mappable property sets. When a message with unmapped references to mapped search keys is sent to a destination in another messaging domain, the references are invalid. To allow these other properties to remain synchronized with the search keys, you can assign them string names in the PS_ROUTING_SEARCH_KEY property set that do not interfere with the names given to any of the core mappable properties. For example, suppose a client needs to transmit a property that contains the search key for the last person in a long routing list. The client can create a named property in the PS_ROUTING_SEARCH_KEY property set called "last_search_key." Because it is stored in a mappable property set, the "last_search_key" property is translated along with the rest of the gateway-mappable properties.


Gateway Mapping Responsibilities

When a MAPI-aware gateway receives a message containing named properties in one of the special property sets designated to contain gateway-mappable properties, the gateway should map all of the properties to the protocol of the destination messaging system. Although MAPI recommends that gateways handle all named properties in the special property sets, gateways are expected to handle only two: e-mail address and address type. Because the e-mail address and address type properties directly affect message transmission, it is critical that gateways support the mapping of these two properties. Because search keys consist of a user's address type and address, they should also be translated if at all possible.

Entry identifiers are not expected to be handled frequently. To enable mapping of an entry identifier that originates in one messaging system to an entry identifier that is usable by another messaging system, the gateway must be able to use the format of both systems. Because most gateways are not aware of entry identifier formats, the translation of entry identifiers is rare.

Another mappable property that is not expected to be translated frequently is the display name. Gateways should store display names and transmit them, but not necessarily translate them.


Event Notification in MAPI

Event notification is the communication of information between two MAPI objects. Through one of the objects, a client or service provider registers an interest in learning of a change or error, called an event, that may take place in the other object. After the event occurs, the first object is informed, or notified. The object receiving the notification is called the advise sink; the object responsible for the notification is called the advise source.

There are three types of advise sink objects; all types are standard MAPI objects:

  • Advise sink objects
  • Form advise sink objects
  • View advise sink objects

Advise sink objects are the most common type. Advise sinks are typically implemented by client applications to receive address book and message store notifications and support the IMAPIAdviseSink interface. IMAPIAdviseSink contains a single method, OnNotify. Form and view advise sinks are less common; they are implemented to receive notifications about changes to custom forms. Form advise sinks support the IMAPIFormAdviseSink interface and view advise sinks support the IMAPIViewAdviseSink interface. Because most clients implement standard advise sink objects, assume that discussions of notifications relate to address book and message store notifications rather than forms notifications. For more information about forms notifications, see Forms Notifications and Writing Form Server Code.

Advise source objects are implemented by service providers and by MAPI. Not all service providers support event notification; it is optional, but strongly recommended. Message store and address book providers usually support object notifications on several of their objects and table notifications on their contents and hierarchy tables. Transport providers do not support notifications directly; they rely on alternative methods of communication with clients.

Unlike advise sinks, advise source objects are not a unique type of MAPI object. Many MAPI objects, such as message stores and tables, can take on the role of advise source. An advise source is any MAPI object that:

  • Implements an Advise method to receive notification registrations.
  • Implements an Unadvise method to receive notification cancellations.
  • Generates notifications of the appropriate type to the appropriate advise sink objects that have registered by calling their IMAPIAdviseSink::OnNotify methods.

Clients implementing advise sink objects call Advise when they want to register for a notification, in most cases passing in the entry identifier of the object with which registration should occur, and Unadvise when they want to cancel the registration. Clients pass a parameter to Advise that indicates which of the several types of events they want to monitor. Advise returns a nonzero number that represents a successful connection between the advise sink and advise source.

Before calling Advise, clients can determine if a message store provider supports notification by checking that the STORE_NOTIFY_OK flag is set in the message store's PR_STORE_SUPPORT_MASK property. There is no way for clients to determine ahead of time whether or not an address book provider supports notifications. Clients must attempt to register and if the attempt fails, they can assume notifications are unsupported.

When an event for which a client has registered occurs, the advise source notifies the advise sink by calling its IMAPIAdviseSink::OnNotify method with a notification data structure that contains information about the event. An advise sink's implementation of OnNotify can perform tasks in response to the notification, such as updating data in memory or refreshing a screen display.

Service providers can implement support for notifications manually or take advantage of the help provided in three IMAPISupport methods: Subscribe, Unsubscribe, and Notify. The Subscribe and Unsubscribe methods handle notification registration and deregistration for providers; the Notify method handles sending notifications when appropriate.

To use the support object methods for notification registration, service providers call IMAPISupport::Subscribe in their Advise methods and pass to Subscribe the advise sink pointer that clients pass to Advise. If an entry identifier is passed as an input parameter to specify an advise source, service providers convert it to a binary key. Subscribe creates a unique connection number and it is this number that service providers return to clients. Service providers can release the client's advise sink object pointer at any time after the Advise call has completed.

When clients call Unadvise to cancel a registration, service providers either decrement the reference count on the client's advise sink pointer or call Unsubscribe to do the same.

When it is time to generate a notification, service providers perform any internal processing that relates to the notification and initializes a NOTIFICATION structure by setting all of its unused members to zero. This technique for initializing the NOTIFICATION structure can help clients create smaller, faster, and less error-prone OnNotify implementations.

The following diagram shows the communication between advise sink objects, advise source objects, and MAPI. MAPI is involved only when the advise source calls the IMAPISupport methods for notification support.


Notification Events

When clients register for event notification, they must specify one or more events of interest. The events that they can specify depend on the set of events that the intended advise source supports. There are ten types of notifications that clients and service providers can register for, each represented by a constant. Status object notification is an exception. Status object notification is an internal MAPI notification; clients cannot register for it and service providers cannot generate it. The following table describes the types of events and the advise source objects that can support them. The event constant is included with the event type.

Event type | Description | Advise source objects
Critical error (fnevCriticalError) | A global error or event has occurred, such as a session shutdown in progress. | Session, all types of message store and address book objects, table, status
Object modified (fnevObjectModified) | A MAPI object has changed. | Folders, messages, all types of address book objects
Object created (fnevObjectCreated) | A MAPI object has been created. | Folders, messages, all types of address book objects
Object moved (fnevObjectMoved) | A MAPI object has been moved. | Folders, messages, all types of address book objects
Object deleted (fnevObjectDeleted) | A MAPI object has been deleted. | Folders, messages, all types of address book objects
Object copied (fnevObjectCopied) | A MAPI object has been copied. | Folders, messages, all types of address book objects
Extended event (fnevExtended) | An internal event defined by a particular service provider has occurred. | Any advise source object
Search complete (fnevSearchComplete) | A search operation has finished and the results of the search are available. | Folders
Table modified (fnevTableModified) | Information in a MAPI table object has changed. | Tables
New mail (fnevNewMail) | A message has been delivered and is waiting to be processed. | Message store, folders

The extended event is defined by a service provider to represent an event that cannot be covered by any of the other predefined events. Only clients that know before they register that a service provider supports an extended event can register for that event. It is not possible for clients to determine without advance knowledge if a service provider supports an extended event and, if it does, how to handle such an event when it is received.


Forms Notifications

Registering for and handling notifications from form objects is a different process than for other MAPI objects. Advise sinks for form notifications implement either the IMAPIViewAdviseSink or IMAPIFormAdviseSink interface rather than IMAPIAdviseSink. IMAPIViewAdviseSink and IMAPIFormAdviseSink each have multiple methods, one for each of the possible events that the corresponding advise source is capable of generating. For example, IMAPIFormAdviseSink has two methods: OnChange to handle a change to the form viewer's status and OnActivateNext to display a new message with the correct form.

The event handling strategy for forms is similar to the event handling strategy implemented in OLE. Clients do not register for specific event types as they do for most MAPI objects. The assumption is that registering for notification enables them to receive any type of event that can be generated by the particular advise source. Because IMAPIAdviseSink::OnNotify must be written so as to handle all registered events, implementing it can be complex for clients that register for many different events. Because the methods in the form advise sink objects target a single event, implementing these methods is simpler.


Threading in MAPI

A thread is the basic entity to which a 32-bit operating system allocates CPU time. A thread has its own registers, stack, priority, and storage, but shares an address space and process resources such as access tokens. Threads also share memory, with one thread reading what another thread has written.

MAPI clients and service providers use the following generic threading models.

Threading model | Description
Single threading model | All objects are used on the single thread.
Apartment threading model | An object can be used only on the thread that created it.
Free threading, or thread-party, model | An object can be used on any thread.

MAPI and MAPI service providers use the free threading model, supporting thread-safe objects that can be used on any thread at any time. The current version of OLE uses the apartment threading model. The apartment threading model supports objects that must be explicitly transferred when a thread other than the one that created the object needs to use that object.

The mechanism that OLE uses to transfer objects from one thread to another is known as marshaling. Marshaling involves a stub object and a proxy object. These special objects package the parameters of the interface in the object to be marshaled, transfer these parameters to the other thread, and unpackage them upon arrival. Conflict between the two multithreaded models arises when a free-threading MAPI object is sent to another process using OLE "lightweight" Remote Procedure Call, or LRPC. LRPC changes the object's semantics from free threading to apartment threading by interposing stub and proxy interfaces with apartment threading behavior between the object and its caller. Awareness of the situations in MAPI that lead to this conflict can help clients and service providers prevent problems from occurring.

A MAPI object can be accessed:

  • Through direct calls to its methods using an interface pointer returned by a service provider or MAPI linked to the client's process, such as the session object returned from MAPILogonEx.
  • Through indirect calls to its methods using an interface pointer returned by any service provider, such as the folder object copied from another folder in IMAPIFolder::CopyFolder.
  • Through a callback function, such as the IMAPIAdviseSink::OnNotify method passed to a service provider or to MAPI in an Advise call or the methods that can show progress on a lengthy operation.


Using Thread-Safe Objects

Client applications and service providers can assume that objects used directly or as callbacks are always thread-safe except in the following cases:

  • A transport provider's status object obtained through a client call to IMAPISession::OpenEntry with an entry identifier from the provider's status table row.
  • All MAPI form objects obtained through a client call to MAPIOpenFormMgr. Form objects obey apartment model rules and clients must use them and all objects contained by them only on the thread that created them.

When a client accesses a transport provider's row in the status table that includes the entry identifier of the associated status object, the client can call OpenEntry with that entry identifier to open the status object. This status object is not thread-safe because transport providers run in the context of the MAPI spooler and do not maintain a separate context for their status object. The status object obeys apartment model rules and clients must use it only on the thread that created it.

A client must also invoke MAPIInitialize on every thread before using any MAPI objects and MAPIUninitialize when that use is complete. These calls should be made even if the objects to be used are passed to the thread from an external source. MAPIInitialize and MAPIUninitialize can be called from anywhere except from within a Win32 DLLEntryPoint function, a function that is invoked by the system when processes and threads are initialized and terminated, or upon calls to the LoadLibrary and FreeLibrary functions. Clients should not need to use DLLEntryPoint functions because the MAPI service provider interface has its own initialization and deinitialization entry points.

Indirect use objects should never be assumed to be thread-safe. Indirect use objects are returned by methods that require destination interface pointers as input parameters. Examples of such methods are IMAPIProp::CopyTo and CopyProps, IMAPIFolder::CopyFolder and CopyMessage, and IMsgServiceAdmin::CopyMsgService. If a service provider wants to call such an object from a thread other than the one on which it was passed, the provider is responsible for explicitly marshaling the object.


Implementing Thread-Safe Objects

With objects that are returned from interface method calls directly, it is the provider's responsibility to ensure thread-safety. With callback objects, it is the client's responsibility. A service provider implements a thread-safe object by serializing access to shared data within the object, insuring that one thread does not inadvertently replace the work of another thread. A service provider can implement serialized access to data in three ways:

  • Provide every object with its own critical section, calling the Win32 API function EnterCriticalSection at the beginning of every method and LeaveCriticalSection at the end. Most of the samples in the MAPI SDK use this method. This option has two drawbacks: a high overhead and the possibility of deadlock. Deadlock can occur if, for example, the thread-safe object calls the MAPI support object or an object returned indirectly through one of the copy methods.
  • Use a single critical section for all objects, calling EnterCriticalSection when the provider is loaded and LeaveCriticalSection when the provider is unloaded. This option provides the most simplicity, but suffers in performance when used with multithreaded clients.
  • Create a small number of critical sections to be associated with crucial shared data structures. The data is isolated from the object, placed, for example, in memory or in a parent object. Access to the data is handled through an internal interface. This option offers the best balance between performance and simplicity.

A client can implement a thread-safe notification callback by calling the MAPI utility HrThisThreadAdviseSink. HrThisThreadAdviseSink transforms a non-thread-safe advise sink into a thread-safe one. For progress callbacks, there is no such utility at this time. A client can choose to use the MAPI thread-safe progress object or create one manually.

A thread-safe object might or might not also be thread-aware. A thread-aware object maintains a separate context for every thread that is using it. Service providers are not required to support thread-awareness in their thread-safe objects, although supporting thread-awareness can be useful in some situations. Two MAPI tables always provide their own context by definition. One table used on different threads does not and should not provide unique context.

A client can choose between receiving notifications on the same thread that was used for the MAPIInitialize call, on the same thread that was used for the Advise call, or on a separate thread owned by MAPI. To ensure that notifications arrive on the same thread that was used to call MAPIInitialize, a client calls MAPIInitialize and passes zero in the ulFlags member of the MAPIINIT_0 structure. Notifications are then delivered during the main message loop.

To receive notifications on the MAPI-owned thread, a client calls MAPIInitialize with the ulFlags member of the MAPIINIT_0 structure set to MAPI_MULTITHREAD_NOTIFICATIONS. The Advise call is made with the client's advise sink object rather than a wrapped version.

To ensure that notifications arrive on the same thread that was used to call Advise, a client calls HrThisThreadAdviseSink and passes the newly created wrapped advise sink to Advise rather than the original advise sink. MAPIInitialize can be called with either flag value.


Validation in MAPI

Implementers and users of interface methods need to validate all types of data from simple integer values to object pointers. Depending on the source of the data and its type, MAPI provides guidelines for validation. Standard guidelines work to ensure consistent and accurate validation, an important feature that helps to promote interoperability between MAPI components.


Validating Parameters to Interface Methods

Interface method implementers can perform two types of validation:

  • Debug validation whereby the implementer displays the values of the input parameters and provides verbose information should there be errors, optionally calling a macro provided by MAPI.
  • Full validation whereby the implementer calls a macro provided by MAPI to check that all necessary parameters are present and set to valid values.

The type of validation performed depends on the caller. When the caller is MAPI or a service provider, debug validation is adequate because MAPI and service providers are expected to pass parameters correctly. When the caller is a client, however, full validation is recommended. Service providers cannot and should not count on clients to always pass appropriate parameters.

MAPI performs debug validation in those interface implementations that are called internally or by service providers and full validation in the implementations that are called by clients. All functions and the utility interfaces, ITableData and IPropData, perform debug validation.

For every interface method, there are three macros that clients and service providers can call in their implementations. Clients and providers can use one macro for debug validation and the other two for full validation. One of the macros for full validation is called for methods that return HRESULT values and the other is called for methods that return unsigned long values.

These macros conform to a three part naming convention with each part separated by an underscore. The prefix identifies the macro being called, as described in the following table.

Macro name prefix | Description
Validate | Identifies a macro to be used for fully validating methods that return HRESULT values.
UlValidate | Identifies a macro to be used for fully validating methods that return unsigned long values.
CheckParameters | Identifies a macro to be used for performing debug validation.

The other two parts identify the interface and method being validated. For example, to fully validate IMAPIProp::GetProps, a method that returns an HRESULT value, service providers call Validate_IMAPIProp_GetProps. To perform debug validation for this method, service providers call CheckParameters_IMAPIProp_GetProps.

The parameters to these macros vary slightly depending on whether the call is being made in C or C++. As with calls made to interface methods, the first parameter in C must be a pointer to the object implementing the method. In C++, the this pointer should be the first parameter. The rest of the parameters are the same in either language; they are the same parameters that are passed to the method being validated. Therefore, the number and type of parameters passed to a validation macro varies depending on the method being validated. All parameters passed to the method must be passed to a validation macro.

The three types of validation macros are platform independent; they are guaranteed to work on both RISC and Intel platforms. Their predecessors, the ValidateParameters, UlValidateParameters, and CheckParameters functions, perform the same functionality as the macros. However, these functions are available only for Intel platforms. Clients and service providers operating on RISC platforms must use the validation macros.

The ValidateParameters and UlValidateParameters macros and functions:

  • Examine the validity of read and write pointers.
  • Examine the validity of structures.
  • Examine the validity of reserved flags.
  • Examine the incoming size of parameters if there is a size limit.

The CheckParameters macro and function are intended to be used by service providers in method implementations that are called by MAPI. They do not perform any real checking of parameters; they supply assert statements. Because the parameters passed by MAPI should be assumed to be correct, service providers do not need to perform full validation in these methods.

The following code samples illustrate how to call the ValidateParameters macro in C and C++. The method being validated is IMAPITable::QueryRows, a method implemented by service providers that returns an HRESULT value and requires three parameters: the number of rows that are requested, a bitmask of flags, and the address of a pointer to an SRowSet structure.

For C, the validation occurs as follows:

STDMETHODIMP Table_QueryRows(LPTABLE lpTable, LONG lcRows,
                             ULONG ulFlags, LPSRowSet FAR * lplprows)
{
    Validate_IMAPITable_QueryRows(lpTable, lcRows, ulFlags, lplprows);

    // rest of method implementation
}

For C++, this example would be written as follows:

STDMETHODIMP CTable::QueryRows(LONG lcRows, ULONG ulFlags,
                               LPSRowSet FAR * lplprows)
{
    Validate_IMAPITable_QueryRows(this, lcRows, ulFlags, lplprows);

    // rest of method implementation
}


Validating Object Pointers

The need to validate object pointers arises when calls are made to retrieve MAPI objects or when private method calls are made within your client or service provider. It is always a good idea to validate these pointers. However, unlike parameter validation, MAPI does not provide a single API function to use. Instead there is a recommended series of steps to ensure that object pointers given to your client or service provider are valid. Not all steps are appropriate for all situations; the vtable verification step, for example, is unnecessary in C++.

To validate object pointers
  1. Check that the object pointer points to the correct amount of writeable memory.
  2. Check that the vtable of the object contains the expected number of readable entries.
  3. Check that one or more methods in the vtable have the expected address.
  4. Check that the object's reference count is nonzero.

MAPI provides two API functions for validating pointer memory: IsBadWritePtr and IsBadReadPtr. The following C code sample illustrates how to validate an object pointer using all of the steps outlined above and these two API functions.

if (IsBadWritePtr(lpMyObject, sizeof(MYOBJECT)))
    return failure

if (IsBadReadPtr(lpMyObject->lpVtbl, size(MYOBJECT_Vtbl)))
    return failure

if (lpMyObject->lpVtbl->SetProps != MYOBJECT_SetProps)
    return failure

if (lpMyObject-> cRef == 0)
    return failure


Validating Data Structures

Standard MAPI data structures are often passed between methods. MAPI provides several API functions to check the validity of these structures. The following table describes the common functions used by clients and service providers to validate MAPI data structures.

Validation function | Purpose
FBadColumnSet | Validates an array of property tags.
FBadEntryList | Validates a list of entry identifiers.
FBadProp | Validates a single property value.
FBadPropTag | Validates a single property tag.
FBadRestriction | Validates a restriction.
FBadRglpNameID | Validates an array of name identifiers.
FBadRglpszW | Validates an array of Unicode strings.
FBadRow | Validates a single row in a table.
FBadRowSet | Validates a set of rows in a table.
FBadSortOrderSet | Validates a sort order for a table.


Structured Storage

Structured storage refers to the hierarchical organization of storage introduced with OLE. In a structured storage environment, storage is organized into two or three types of objects:

  • Stream objects
  • Lock bytes objects
  • Storage objects

Stream and lock bytes are lower-level objects that directly access the data. Stream objects implement the IStream interface which defines methods for reading, writing, positioning, and copying bytes of data. Lock bytes objects implement another OLE interface, ILockBytes, to access data with a byte array. Byte arrays are typically used to provide customized access to underlying storage.

Storage objects are layered on top of the stream or lock bytes objects; they can contain one or more of these objects as well as other storage objects. Storage objects implement the IStorage interface which defines methods for creating, accessing, and maintaining nested objects.

Because IStream, ILockBytes, and IStorage are OLE interfaces rather than MAPI interfaces, their methods return OLE error values rather than MAPI values. Clients and service providers calling methods in these interfaces must use the API function MapStorageSCode to translate these values into MAPI error values.

Clients and service providers use structured storage for working with properties that are too large to maintain with the IMAPIProp methods, typically large string and binary properties. One of the common ways that clients or service providers access them is by specifying IStream or IStorage as the interface identifier in a call to the IMAPIProp::OpenProperty method. For example, clients call OpenProperty with PR_ATTACH_DATA_BIN as the property tag and IID_IStream as the interface identifier to access a binary attachment in a message.

Clients and service providers can implement their own stream and storage objects or call API functions to access implementations supplied by MAPI or OLE. Because the supplied implementations serve most purposes, clients and service providers rarely need to create their own.

When a client calls OpenProperty on a MAPI object to access one of its properties through a storage object, the service provider will typically open the storage object in direct mode. However, this is typical rather than required behavior. Clients should assume that all storage objects opened or created by service providers are transacted and require a call to IStorage::Commit. They should also remember that changes to storage objects will not be made permanent until they call IMAPIProp::SaveChanges after the final Commit to save the MAPI object.

MAPI and OLE provide several API functions for defining or accessing storage and stream objects. The commonly used functions are described in the following table.

Function | Description
CreateDocfile | Creates a general purpose storage object.
HrIStorageFromStream | Creates a storage object to access a stream or lock bytes object.
OpenIMsgOnIStg | Creates a message object to access a storage object.
OpenStreamOnFile | Creates a stream object to access a file.
WrapCompressedRTFStream | Creates a stream object that contains the compressed or uncompressed version of a stream holding the rich text of a message.

CreateDocfile is used frequently in OLE and in MAPI to create a storage object. For more information on this function, refer to the OLE documentation.

To retrieve the names of the streams in a given substorage
  1. Call the substorage's IStorage::EnumElements method to get an IEnumSTATSTG interface.
  2. Call IEnumSTATSTG::Next with as many STATSTG structures at a time as you can. If you ask for 100 at a time, Next will usually return S_FALSE with the contents of pceltFetched set to the number that were actually retrieved.
  3. Check for the STATSTG structures that are flagged with STGTY_STREAM.
  4. Release the pwcsName parameter.
To create a storage object to access an existing stream or lock bytes object
  • Clients call HrIStorageFromStream.
To create a message object to access an existing storage object
  • Service providers and clients call OpenIMsgOnIStg. The message object that is created differs from the message objects typically created by message store providers in that it does not support all of the IMessage interface methods, such as IMessage::SubmitMessage.

    An optional input parameter to OpenIMsgOnIStg is a callback function that conforms to the MSGCALLRELEASE prototype. This function is called by the new message object when the message's reference count reaches zero. Implementing a MSGCALLRELEASE function can be useful for performing final processing before the new message is completely removed.

OpenStreamOnFile is commonly used for storing file attachments because it creates a stream that reads from and writes to a file. OpenProperty with PR_ATTACH_DATA_BIN as the property tag creates a stream for storing binary attachment data.

To compress or uncompress a stream containing message text in the Rich Text Format
  • Clients call WrapCompressedRTFStream. WrapCompressedRTFStream creates a stream that wraps the RTF stream. The wrapper stream does not implement all of the IStream methods; the following methods are excluded:

    Seek

    SetSize

    Revert

    LockRegion

    UnlockRegion

    Stat

    Clone

    Because the stream objects created by WrapCompressedRTFStream do not support either SetSize or Stat, there is not an easy way to either extend or retrieve their size. The best strategy is to pick a reasonable buffer size and read or write in a loop.

Note OLE has a storage object implementation based on a byte array that returns an IEnumSTATSTG object from the EnumElements method that is problematic. In particular, the QueryInterface method does not work correctly. Service providers that implement their own storage objects using the OLE implementation should create a thin wrapper for the IEnumSTATSTG object that forwards calls on to the underlying IEnumSTATSTG methods but implements its own AddRef, Release, QueryInterface, and Clone methods.


Character Sets

MAPI-compliant client applications and service providers can use ANSI characters (single byte) or Unicode characters (double byte). OEM character sets are not supported; an OEM string passed to a MAPI method or function will cause that method or function to fail. Client applications that work with filenames in the OEM character set must be careful to convert them to ANSI before passing them to a MAPI method or function.

Supporting the Unicode character set is optional, both for clients and service providers. All service providers should write their code so that they can compile the same regardless of whether or not they support Unicode. Clients compile conditionally, depending on their level of support, but service providers do not. They should not have to be recompiled when the character set changes. Nothing in service provider code should be conditional.

When clients or service providers that support Unicode make a method call that includes character strings as input or output parameters, they set the MAPI_UNICODE flag. Setting this flag indicates to the implementation that all incoming strings are Unicode strings. On output, setting this flag requests that all strings passed back from the implementation should be Unicode strings if possible. Method implementers that support Unicode will comply with the request; method implementers that do not provide Unicode support will not comply. String properties that are not in Unicode format are of type PT_STRING8.

MAPI defines the fMapiUnicode constant in the header file MAPIDEFS.H to represent the default character set. If a client or service provider supports Unicode, fMapiUnicode is set to MAPI_UNICODE. Clients and service providers that do not support Unicode set fMapiUnicode to zero.

Service providers that do not support Unicode should:

  • Refuse to perform conversions between character sets.
  • Never pass the MAPI_UNICODE flag in method calls.
  • Return MAPI_E_BAD_CHARWIDTH when the MAPI_UNICODE flag is passed in.
  • Declare ANSI string properties explicitly.

Service providers can also return MAPI_E_BAD_CHARWIDTH when they only support Unicode and clients do not pass the MAPI_UNICODE flag.

Note The current version of MAPI supports Unicode on the Windows NT platform in the following methods:

IAddrBook::Address

IAddrBook::CreateOneOff

IAddrBook::Details

IAddrBook::ResolveName

IMAPIProp::GetLastError (IAddrBook implementation only)

For these methods, callers can expect any returned strings to be Unicode strings. Character strings returned from MAPI implementations of any other method will be ANSI character strings.


Formatted Text in MAPI

The text of a message can be stored and transmitted using plain text or formatted text. Formatted text enhances the message text by altering its appearance with, for example, one or more fonts, font sizes, or text colors. It is recommended that all clients and whenever possible, all message store providers, support formatted text. Supporting formatted text in messages adds value by improving message readability and making message handling easier and more efficient.

Formatted text can be implemented in a variety of ways. The most common way is with the Rich Text Format (RTF). MAPI defines two transmittable properties for holding message text information: PR_BODY for plain text and PR_RTF_COMPRESSED for RTF text that has been compressed. Because the formatted version of a message text can be twice as large as the version without the formatting, the RTF text is compressed before it is transferred with the message and stored in the PR_RTF_COMPRESSED property. When it is time to display the message on the screen, it is uncompressed using a utility function provided by MAPI.

MAPI defines these two message text properties and mechanisms for conversion between them so that RTF-aware clients can interoperate with clients and messaging systems that do not support formatted text.


Synchronizing Text and Formatting

The main challenge in sending Rich Text Format (RTF) messages is keeping the text synchronized with the formatting. To ensure that when messages arrive at their destination they are as their originators intended and that the text and formatting are synchronized, MAPI provides the RTFSync function. RTFSync is typically called by RTF-aware clients before displaying incoming messages and by the MAPI spooler when it downloads messages to a transport provider. Callers specify the area of possible discrepancy by passing one or two flags to RTFSync:

  • RTF_SYNC_BODY_CHANGED to indicate a modification in message text.
  • RTF_SYNC_RTF_CHANGED to indicate a modification in message formatting.

The synchronization process that occurs in RTFSync is a sophisticated cyclic redundancy check (CRC) of the message text that ignores some characters and converts others. Characters that most likely were added by transport providers are ignored. MAPI defines several properties for working with RTF as described in the following table.

RTF property | Description
PR_RTF_SYNC_BODY_TAG | Indicates the beginning of the real message text.
PR_RTF_SYNC_BODY_CRC | Contains the result of the cyclic redundancy check of the message text.
PR_RTF_SYNC_BODY_COUNT | Contains the number of characters in PR_RTF_SYNC_BODY_CRC.
PR_RTF_IN_SYNC | Set to TRUE when the message text and formatting have been synchronized.
PR_RTF_SYNC_PREFIX_COUNT | Contains the number of nonwhitespace characters that preceed the message text.
PR_RTF_SYNC_TRAILING_COUNT | Contains the number of nonwhitespace characters that trail the message text.


Supporting Formatted Text in Outgoing Messages: Client Responsibilities

Clients set either the PR_BODY property, the PR_RTF_COMPRESSED property, or both properties for an outgoing message. Clients that support only plain text set only the PR_BODY property. Rich Text Format (RTF)-aware clients might set both properties or only PR_RTF_COMPRESSED, depending on the message store provider being used.

It is important for a client to check its message store's PR_STORE_SUPPORT_MASK property to determine whether the store supports RTF. If the message store is not RTF-aware, an RTF-aware client sets both the PR_BODY and PR_RTF_COMPRESSED properties for each outgoing message.

If the message store is RTF-aware, only the PR_RTF_COMPRESSED property needs to be set.

To set PR_RTF_COMPRESSED and ensure that the synchronization process occurs as necessary, RTF-aware clients
  1. Call the IMAPIProp::OpenProperty method to open the PR_RTF_COMPRESSED property, setting both the MAPI_CREATE and MAPI_MODIFY flags. MAPI_CREATE ensures that any new data replaces any old data and MAPI_MODIFY enables you to make those replacements.
  2. Call the WrapCompressedRTFStream function, passing STORE_UNCOMPRESSED_RTF if the message store sets the STORE_UNCOMPRESSED_RTF bit in its PR_STORE_SUPPORT_MASK property, to get an uncompressed version of the PR_RTF_COMPRESSED stream returned from OpenProperty.
  3. Write the message text data to the uncompressed stream returned from WrapCompressedRTFStream.
  4. Commit and release both the uncompressed and compressed streams.

At this point, if the message store provider supports RTF, you have done all that is required. You can depend on the message store provider to handle the synchronization process and the creation of the PR_BODY property, if necessary. However, if the message store provider does not support RTF, you must call the RTFSync function to synchronize the text with the formatting, setting the RTF_SYNC_RTF_CHANGED flag.


Supporting Formatted Text in Incoming Messages: Client Responsibilities

As messages are transferred between messaging systems, the MAPI spooler makes sure that the rich text formatting remains synchronized with the message text. The MAPI spooler calls the RTFSync function from within a wrapped version of the message that it passes to the transport provider. The transport provider saves the changes made to the message by calling the IMAPIProp::SaveChanges method and then routes it to the new recipient.

When the recipient's RTF-aware client application opens the message to display the text, it must synchronize the text with the formatting and open either PR_RTF_COMPRESSED or PR_BODY, depending on which property is available.

To open a message, RTF-aware clients
  1. Call RTFSync to synchronize the message text with the formatting if the message store is not RTF-aware. The RTF_SYNC_BODY_CHANGED flag should be passed in the ulFlags parameter if the PR_RTF_IN_SYNC property is missing or set to FALSE. Clients working with RTF-aware message stores need not make the RTFSync call because the message store takes care of it.
  2. Call IMAPIProp::SaveChanges if the message text has been updated.
  3. Call IMAPIProp::OpenProperty to open the PR_RTF_COMPRESSED property. If PR_RTF_COMPRESSED is not available, you should open the PR_BODY property instead to display the message content.
  4. Call the WrapCompressedRTFStream function to create an uncompressed version of the compressed RTF data, if available.
  5. Display the uncompressed RTF data or the plain text data to the user.

RTFSync returns a Boolean value that indicates whether or not the message has been updated. If this value returns TRUE, call SaveChanges at some point to make the update permanent. The call does not have to be made immediately after RTFSync returns.

Note Because so many components handle the formatted text before you receive it, there is the possibility of corruption. This corruption could come from the message store provider, a third party application, a gateway, or a transmission error.


Supporting Formatted Text: Message Store Responsibilities

Message store providers use the PR_STORE_SUPPORT_MASK property to publish whether or not they can handle Rich Text Format (RTF) and, if they are RTF-aware, whether they store the formatted text in a compressed or uncompressed format. Message store providers indicate that they are RTF-aware by setting the STORE_RTF_OK bit and that they store the formatted text in an uncompressed form by setting the STORE_UNCOMPRESSED_RTF bit.

While it is important for an RTF-aware client to check for the STORE_RTF_OK bit to determine whether or not a message store supports RTF, it is not necessary for a client to be concerned with the format of an RTF-aware store's formatted text.

All message stores must support non-RTF-aware clients. A non-RTF-aware message store must delete the PR_RTF_IN_SYNC property during a call to the message's IMAPIProp::SaveChanges method if a client has changed PR_BODY without updating either PR_RTF_IN_SYNC or PR_RTF_COMPRESSED. Deleting PR_RTF_IN_SYNC causes the PR_RTF_COMPRESSED property to be recomputed from the PR_BODY property the next time an RTF-aware client calls RTFSync.

Most RTF-aware message stores are not given the message text by clients; it must be computed on request. Because this computation is time consuming and expensive, clients should use PR_RTF_COMPRESSED whenever possible. To compute the PR_BODY property, the message store provider must uncompress the contents of the PR_RTF_COMPRESSED property and remove the rich text formatting. Clients that do not support the PR_RTF_COMPRESSED property require this computation to take place for every message.

When copying messages, message store providers that do not use the IMAPISupport::DoCopyProps or IMAPISupport::DoCopyTo methods run the risk of creating a message with no content if their implementation excludes the PR_BODY property and relies on PR_RTF_COMPRESSED. It is possible for the data in the PR_RTF_COMPRESSED property to be corrupt. Before excluding either of these message content properties in the copy operation, check for corruption as follows:

  1. If the value of PR_RTF_COMPRESSED is not larger than the compressed RTF, the property is corrupt.
  2. If the magic value in the RTF header is not dwMagicCompressedRTF or dwMagicUncompressedRTF, the property is corrupt.

Message store providers using the support methods need not be concerned with implementing a check for PR_RTF_COMPRESSED corruption; MAPI ensures that the appropriate properties exist and are valid.

There are three different levels of RTF support that message store providers can implement; MAPI recommends that RTF-aware message store providers implement their support at the middle or highest level. All RTF-aware message store providers take care of generating PR_BODY from the data included in PR_RTF_COMPRESSED on outgoing messages and make a call to RTFSync to synchronize text and formatting on incoming messages.

The differences between these three levels are described in the following table.

Level of support | Description
Low | Message store provider calls RTFSync whenever changes are saved to a message and extracts the data for the PR_BODY property from PR_RTF_COMPRESSED rather than requiring clients to set it. Both PR_BODY and PR_RTF_COMPRESSED are stored.
Middle | Message store provider stores only the PR_RTF_COMPRESSED property, computing PR_BODY when necessary.
High | Message store provider stores neither PR_BODY or the auxilliary RTF properties. RTFSync is called when the message text has changed and the formatting remains unchanged or when a new message is downloaded by a transport provider.


Supporting Formatted Text: Rendering Attachments

A client that cares about where in a message its attachments are rendered sets the PR_RENDERING_POSITION property for these attachments during message composition. A client that does not care about rendering placement leaves this property unset.

When a client opens a message with attachments, it attempts to retrieve each attachment's PR_RENDERING_POSITION property to determine where in the message text the attachment should be rendered. A client can use one of the following methods to retrieve PR_RENDERING_POSITION:

  • IMAPIProp::GetProps on the open attachment to retrieve the PR_RENDERING_POSITION property.
  • IMessage::GetAttachmentTable on the open message to retrieve its attachment table. PR_RENDERING_POSITION is a required column in all attachment tables. This is the preferred method because it results in better performance.

RTF-aware message stores can choose whether to return an accurate or approximate value for PR_RENDERING_POSITION. Because message stores recalculate an attachment's PR_RENDERING_POSITION value when asked for the message's PR_BODY property, some RTF-aware message stores only guarantee the accuracy of rendering positions when a client asks first for PR_BODY. RTF-aware message stores are allowed to provide clients with approximate rendering position values to enhance performance. Providing an approximate rather than an accurate rendering position saves time and is sufficient for most situations.

RTF-aware message stores should base their approximation on the value specified by the client responsible for creating the attachment. Although all clients should set PR_RENDERING_POSITION, message store providers should be prepared to deal with the possibility of its absence. When the client does not set PR_RENDERING_POSITION, a message store can set it to -1 to indicate that the rendering position is not within the message text. Attachments with a rendering position of -1 can be displayed at any place within the message depending on the client. Many clients position these types of attachments at the top of the message.

The degree of accuracy for a PR_RENDERING_POSITION property depends on whether or not a message store saves both a message's PR_BODY and PR_RTF_COMPRESSED properties or only PR_RTF_COMPRESSED. If the client generates PR_BODY and the message store saves it along with the formatted text, the rendering positions will be accurate. However, if the message store must generate its own version of PR_BODY because it only saves PR_RTF_COMPRESSED, it is probable that the rendering positions will be somewhat inaccurate. This is because of the differences in the way that clients and message store providers generate the PR_BODY property.

To calculate an accurate PR_RENDERING_POSITION value, an RTF-aware store uses a tag embedded in the formatted text. The utility function RTFSync can be called to perform this calculation and update an attachment's rendering position. Depending on the amount of state information available, the message store can pass either RTF_SYNC_BODY_CHANGED, RTF_SYNC_RTF_CHANGED, or both values to RTFSync.


Supporting Formatted Text: Gateway Responsibilities

To handle Rich Text Format for outgoing messages, gateways
  1. Retrieve only a message's PR_RTF_COMPRESSED property from the message store. The main advantage in retrieving only the PR_RTF_COMPRESSED property is that the message text does not need to be sent between machines if the gateway and the message store exist on different machines.
  2. Generate the message text from the formatted text either by calling the RTF library function HrTextFromCompressedRTFStream or, if the message is stored locally, RTFSync. The RTF_SYNC_RTF_CHANGED flag should be set in the call to RTFSync.
  3. Make any irreversible modifications to the message text, such as dropping unsupported characters.
  4. Ensure that both PR_RTF_IN_SYNC and all of the RTF auxilliary properties are either set or absent.
  5. If any modifications were made, call RTFSync with both the RTF_SYNC_RTF_CHANGED and RTF_SYNC_BODY_CHANGED flags set. RTFSync will recalculate the RTF auxilliary properties from the modified text.
  6. Make any reversable modifications to the message text, such as inserting attachment placeholders and performing nondestructive code page conversions.
  7. Send the message.
To handle Rich Text Format for incoming messages, gateways
  1. Reverse any message text modifications that were made directly before the message was sent.
  2. Call RTFSync if the message contains both the PR_RTF_COMPRESSED and PR_BODY properties.
  3. Update the message in the message store with the PR_RTF_COMPRESSED property if the message contains it; update with the PR_BODY property only if PR_RTF_COMPRESSED is absent.
  4. Discard PR_BODY if the message contains both this property and PR_RTF_COMPRESSED.

Gateways call RTFSync to avoid transmitting both the message text and formatted text if the message store is on a different machine. If the gateway is local, it can set both properties and allow the message store to perform the synchronization.


Idle Engine

MAPI provides several functions that are collectively known as the idle engine. These functions allow clients, address book providers, and message store providers to perform various tasks during slow times in the session or in response to a slow time. For example, clients and service providers can defer slow operations or close files that have remained unused for a lengthy period. Transport providers typically do not use the idle engine because the IXPLogon::Idle method takes its place.

To use the idle engine, clients and service providers create a callback function that contains the tasks that should occur when the MAPI subsystem is idle. When MAPI detects idle time, it invokes this callback function. The callback function follows the FNIDLE prototype, defined as follows:

BOOL (STDAPICALLTYPE FNIDLE) (LPVOID lpvContext)

The functions that make up the idle engine are:

ChangeIdleRoutine

DeregisterIdleRoutine

EnableIdleRoutine

FtgRegisterIdleRoutine

MAPIDeInitIdle

MAPIInitIdle

To register a callback function, clients and service providers call the FtgRegisterIdleRoutine function. The input parameters include an optional priority, a block of memory that is passed to your callback function as input, an amount of time to be used in any way appropriate, and a set of option flags.

Clients and service providers can specify a priority in the priIdle parameter that controls how the idle function runs or specify zero if priority is not an issue. Because negative numbers represent higher priorities than positive numbers or zero, compression and search operations should be assigned negative numbers. Tasks that occur once should be assigned positive numbers.

To deregister an active callback function, clients and service providers call the DeregisterIdleRoutine function. Because DeregisterIdleRoutine operates asynchronously, it is possible for the callback function to be invoked at any time during the deregister call and possibly even after DeregisterIdleRoutine has returned.

To modify some or all of the characteristics of a callback function, clients and service providers call the ChangeIdleRoutine function. ChangeIdleRoutine makes changes according to how the flags parameter ircIdle is set; ChangeIdleRoutine can change the function itself, its priority, time setting, and input parameter.

MAPI defines idle the same as the operating system, when the operating system has a definition. On Win16, MAPI installs a journalling hook that updates a variable with the time of the last user action. Idle time calculations are based on this variable. On Win32, MAPI creates a thread with idle-class priority to schedule idle tasks. This thread keeps track of the time and posts a message to the thread that is to execute the idle task when the time for its execution arrives. Win32 schedules threads, not processes. If tasks that have a priority higher than the idle priority are occurring on the workstation, the idle task should not get scheduled for execution until the tasks have completed.

All idle tasks run on the thread that called MAPIInitIdle. MAPI has a separate thread for scheduling, but when an idle task becomes eligible, it posts a message back over to the initialization thread and the idle task is executed there. The implications for different types of clients are as follows.

Threading model | Implication
Single-threaded | No problem. Idle functions execute on your client's main thread and are serialized through the message loop.
Free-threaded | Idle functions must be thread-safe, but your client already has the necessary infrastructure. Your client might not need the MAPI idle engine at all.
Apartment-threaded | Idle function has to execute on the same thread that registered it if it wants to use MAPI, OLE, or any other COM interfaces. The most straightforward way is to register an idle function with MAPI that posts a message to the right thread and dispatch the "real" idle function directly from that thread's message loop.


Developing a Client Application

MAPI client applications are applications that are written with the object oriented MAPI client interface. MAPI clients interact with one or more messaging systems through the MAPI subsystem and MAPI-compliant service providers. This interaction can occur in many different ways; there is an enormous variety in client applications. Most clients are messaging clients, either integrating messaging into their established feature set or performing messaging as their primary feature. Other features that MAPI clients might provide include profile administration or address book and message store management.

All messaging clients initialize the MAPI libraries and start a session with the MAPI subsystem. Once a session has been established, a client can:

  • Handle outgoing messages, including replies, forwarded messages, and retransmissions.
  • Handle incoming messages.
  • Handle the message store by opening folders and messages, creating, modifying, copying, and sending messages, tracking conversations, and searching one or more folders.
  • Handle the address book by creating and modifying recipients, locating entries, and traversing the container hierarchy.
  • Handle a transport provider by performing reconfiguration, setting options and transport order, and sending messages on demand.
  • Handle event notification.
  • Handle forms.
  • Handle profiles and message services.

Use the topics in this section to help you implement these basic tasks and the specific features that will make your MAPI client unique.


Types of Client Applications

There are primarily two types of messaging clients: those that handle interpersonal messages (IPM) and those that handle interprocess communication (IPC) messages. Within those types, messaging client applications can be categorized as follows:

  • Person-to-person
  • Person-to-machine
  • Machine-to-person
  • Machine-to-machine
  • Mix of persons and machines

Person-to-person applications involve a person initiating the exchange of messages and another person responding. This category of applications includes traditional e-mail applications as well as more structured exchanges such as document routing or expense approval.

Person-to-machine applications involve a person initiating the exchange of messages and a machine responding. This category includes applications that use e-mail to, for example, submit a database query or subscribe to a mailing list.

Machine-to-person applications involve a machine initiating the exchange of messages and a person responding. This category includes applications that distribute documents such as news feeds and opinion surveys.

Machine-to-machine applications involve a machine initiating the exchange of messages and a machine responding. This category includes applications such as link heartbeat monitoring and directory and database replication.

The final category, a mix of persons and machines, involves a more complex scenario. This category includes applications that do not necessarily transmit messages between senders and recipients. Instead they might post them directly into a public folder or to a bulletin board forum supported by a message store. The messages can then be consumed on demand by other readers, an administrator, or a software agent.

If you are writing a person-to-person application, machine-to-person application, or an application that posts messages to public forums, set up your application to send and receive IPM messages. If you are writing a person-to-machine or machine-to-machine application, it should be set up to send and receive IPC messages. Any application that requires the interaction of a human user must support IPM messages. Applications that involve both people and machines in a variety of scenarios often must support both IPM and IPC messages. The only real difference between the two classes is that IPM messages in a message store are visible to messaging clients, while IPC messages usually are not.

Rather than limiting your messages to the capabilities provided by the MAPI superclasses, IPM and IPC, you can customize and enhance these classes by creating new IPM or IPC subclasses. Creating message subclasses involves inventing new message classes that inherit from the superclasses. For example, if your person-to-person application specializes in sending documents, you can subclass the IPM superclass by defining an IPM.Document.MyDoc class and create properties that describe your documents. In addition to supporting these custom properties, your IPM.Document.MyDoc messages will inherit the properties supported by all IPM messages.


Linking to the MAPI DLLs

MAPI clients can link to the MAPI DLLs implicitly or explicitly through the Windows functions LoadLibrary and GetProcAddress.

MAPI provides type definition statements in the MAPIX.H header file for each of the following functions:

MAPILogonEx

MAPIUninitialize

MAPIInitialize

MAPIAllocateBuffer

MAPIAllocateMore

MAPIFreeBuffer

MAPIAdminProfiles

Use these type definitions to correctly call the corresponding entry points if you link explicitly to the MAPI DLLs.

Service providers can contain non-MAPI functionality — features that are completely unrelated to MAPI — in their DLL. If you need to use these features, call LoadLibrary before using the DLL and FreeLibrary to remove the DLL from memory after its use. Because MAPI is unaware of non-MAPI uses of a service provider DLL, there is no guarantee that the DLL will be available when needed. MAPI releases a service provider DLL when there are no longer any clients with active sessions that require its services.


Session Handling

Before you can communicate with service providers and an underlying messaging system, you must establish a session. A MAPI session is a link from a client to other MAPI components. As the result of successfully starting a session, MAPI returns to clients a pointer to a session object — an object that implements the IMAPISession interface. You can use the methods of the IMAPISession interface to access the objects of address book and message store providers, access several tables, display forms, set transport provider properties, and perform profile and message service administration.


Starting a MAPI Session

Although there is a significant amount of work performed during session start up, the required tasks are minimal. Much of this work is done in the MAPI processing of the MAPIInitialize and MAPILogonEx calls. Both of these functions accept flags as input parameters for controlling aspects of the session such as notification handling and the user interface. It is important to understand the consequences of setting each of these flags when calling MAPIInitialize to initialize the MAPI libraries and MAPILogonEx to log on to the MAPI subsystem.

To start a MAPI session
  1. Call MAPIInitialize to initialize the standard set of MAPI libraries.
  2. If you need to use the OLE libraries, call the OLE function OleInitialize.
  3. If you need to use the MAPI utility library, call ScInitMapiUtil.
  4. Call MAPILogonEx with a valid profile to log on to the MAPI subsystem.

    MAPILogonEx verifies the configuration of each of the service providers in the message services included in the profile, prompting the user for additional information if necessary and possible. When MAPILogonEx completes, the configured service providers are ready for service.


Initializing MAPI

All client applications that use the MAPI libraries must call the MAPIInitialize function. MAPIInitialize initializes global data for the session and prepares the MAPI libraries to accept calls. There are two flags that are important to set in some situations:

MAPI_NT_SERVICE

MAPI_MULTITHREAD_NOTIFICATIONS

Set the MAPI_NT_SERVICE flag if your client is implemented as a Windows NT service. If your client is a Windows NT service and you do not set this flag, MAPI will not recognize it as a service.

The MAPI_MULTITHREAD_NOTIFICATIONS flag relates to how MAPI manages notifications. MAPI creates a hidden window that receives window messages when changes occur to an object generating notifications. The window messages are processed at some point, causing the notifications to be sent and the appropriate IMAPIAdviseSink::OnNotify methods to be called.

MAPI either creates the notification window on the thread that was used for your first MAPIInitialize call or on a separate thread — a thread dedicated to handling notifications. MAPI expects the thread that is used to create the hidden notification window to:

  • Have a message loop.
  • Remain unblocked throughout the life of the session.
  • Have a longer lifetime than any other thread created by your client.

You can choose which thread is used by setting a flag in the first MAPIInitialize call. The danger in allowing one of your threads to handle the notifications is that if the thread disappears, the notification window is destroyed and notifications can no longer be sent to any of your other threads. Also, special processing might be needed to control the dispatching of the notification messages that are posted to the hidden window's message queue.

If you use a separate window to handle notifications, be assured that notifications will appear at the appropriate time on an appropriate thread. You will not need any special code to check for and process the Windows messages that are posted to the notification window.

MAPI recommends that the following types of client applications use a separate thread to create the hidden window for notification support:

  • All 32-bit multithreaded clients
  • Single-threaded Windows NT services and Win 32 console applications
  • Single-threaded clients that do not need to use their main thread for notification

To use the separate thread approach, call MAPIInitialize on every thread, setting the MAPI_MULTITHREAD_NOTIFICATIONS flag. Calls made from 16-bit clients operate as if the MAPI_MULTITHREAD_NOTIFICATIONS flag is not set.

Note Only a client's first call to MAPIInitialize causes a hidden window to be created to support notifications. Subsequent calls only cause a reference count to be incremented.


Initializing OLE for Use with MAPI

If you also use OLE, call the OLE function OleInitialize to initialize the OLE libraries. If your client is written for a 32-bit platform, such as Windows NT or Windows 95, this call must be made on every thread in your application. OleInitialize initializes global data for the session and prepares the OLE libraries to accept calls. For information about calling OleInitialize, see the Platform SDK.


Initializing the MAPI Utilities

If the only part of MAPI that you need to use are the utilities — the interfaces and functions declared in MAPI's MAPIUTIL.H header file such as IPropData and ITableData — you do not need to call MAPIInitialize for initialization. Instead, call the ScInitMapiUtil function. ScInitMapiUtil allows client applications to use utility functions and methods that require MAPI allocators, but that do not ask for them explicitly.

At shutdown time, make a call to DeinitMapiUtil to free resources connected to the utilities. Do not call MAPIUninitialize.

Be aware that the ITableData interface does not support table notifications for clients that have called ScInitMapiUtil rather than MAPIInitialize.


Logging On

Client applications log on to the MAPI subsystem by calling the MAPILogonEx function. MAPILogonEx validates the profile selection and the configuration of each service provider in the profile. Once configured, MAPI starts the address book providers before starting the message store providers. Transport providers are started when their services are first required.

To choose a profile
  • Pass in a character string that represents the name of the profile in the lpszProfileName parameter to MAPILogonEx.

    – Or –

  • Allow the user to enter the profile by passing NULL in the lpszProfileName parameter and setting the MAPI_LOGON_UI flag.

    – Or –

  • Select the default profile by passing NULL in the lpszProfileName parameter and setting the MAPI_EXPLICIT_PROFILE flag.

If you require a specific profile other than the default profile, you must save its name in your own configuration database or use a specific naming convention. MAPI does not expose any profile attributes other than the name and default flag in the profile table, and the default profile flag is reserved for messaging client and related IPM applications.

If the selected profile requires a password, you can specify it in one of two ways.

To specify a password
  • Pass in a character string that represents the password in the lpszPassword parameter.

    – Or –

  • Allow the user to enter the password by passing NULL in the lpszProfileName parameter and setting the MAPI_PASSWORD_UI flag.

Clients that supply partial profile, password, or provider configuration information to MAPILogonEx must prompt the user for the additional data by allowing a dialog box to be displayed. If information is missing and MAPILogonEx cannot prompt the user to supply it, the logon fails. Clients that do not need user input can suppress the dialog box display.

The flags that MAPILogonEx uses to enable a user interface are mutually exclusive; only one can be set. Leaving these flags unset suppresses the display of a user interface, causing MAPILogonEx to fail if necessary information is missing. That is, if you disable the user interface and pass NULL for the lpszProfileName parameter and do not set the MAPI_EXPLICIT_PROFILE flag, MAPILogonEx will fail because it cannot retrieve a profile name.

The session that MAPILogonEx establishes can be an individual messaging session, a shared messaging session, or a nonmessaging session. Individual messaging sessions are private connections between your client and the MAPI subsystem and can be established by setting the MAPI_NEW_SESSION flag in the call to MAPILogonEx.

Shared messaging sessions are connections that multiple messaging clients can use. Shared sessions are typically established for clients that are members of a workgroup and use the same profile. To establish a new session as a shared session, set the MAPI_ALLOW_OTHERS flag.

To use an existing shared session
  • Do not set the MAPI_NEW_SESSION flag.
  • Do not set the MAPI_ALLOW_OTHERS flag.
  • Pass NULL for the lpszProfileName parameter.
  • Pass NULL for the lpszPassword parameter.

Nonmessaging sessions allow clients to access the MAPI subsystem, but do not allow messages to be sent or received. Configuration or administration applications are examples of clients that might need to establish nonmessaging sessions. To request a nonmessaging session, set the MAPI_NO_MAIL flag. Setting this flag logs your client on without informing the MAPI spooler. Clients that log on to MAPI with this flag cannot expect to ever receive read status reports.

The MAPI_NO_MAIL flag should only be set:

  • If your client will not send or receive messages during the session.
  • If your client has complete control over the contents of the profile and messages are sent and received using only the Microsoft Exchange default message store and transport providers.

A messaging client can share a session with a nonmessaging client. The characteristics of one member of a shared session are not affected by the characteristics of other members. That is, if you log on with the MAPI_NO_MAIL and MAPI_ALLOW_OTHERS flags set, a messaging client logging on to your session has no affect on the operation of your client and vice versa. The messaging client will still be able to send and receive messages and your client will not.

MAPILogonEx defines a few other flags that you can set:

  • MAPI_FORCE_DOWNLOAD indicates that incoming messages should be downloaded before MAPILogonEx returns. Not setting this flag causes messages to be downloaded in the background at a later time.
  • MAPI_SERVICE_UI_ALWAYS requests that every message service in the profile display a configuration dialog box.
  • MAPI_NT_SERVICE indicates that your client is implemented as a Windows NT service. This flag must be set if your client is a service.

With every successful logon, MAPILogonEx returns a pointer to a MAPI session. You can use this pointer to call the methods of the IMAPISession interface. Session pointers, regardless of the type of session, are unique to the clients that receive them and are not valid across tasks.


Ending a MAPI Session

Clients can end their sessions in response to a user's request, either immediately or after all outbound messages have been processed, and when a critical error occurs. Some clients need to stay logged on so that pending outbound messages can reach the transport provider and the destination messaging system. If such a client sends a message and immediately logs off, the message remains in the outgoing queue until a user logs back on and stays logged on long enough for the message to be transmitted.

When you need to terminate your session with the MAPI subsystem
  1. Cancel the registrations for all notifications by calling the Unadvise method of every registered object.
  2. Release all open objects by calling their IUnknown::Release methods. The types of open objects can include advise sinks, the status table, the Outbox folder, one or more message stores, and the address book.
  3. Call MAPIFreeBuffer to free the memory for any cached entry identifiers, such as PR_IPM_SUBTREE_ENTRYID.
  4. Call IMAPISession::Logoff, setting the MAPI_LOGOFF_UI flag if you allow a user interface and the MAPI_LOGOFF_SHARED flag if you own the current shared session. Logoff notifies all other clients that are using the current shared session that they should log off by sending an error notification.
  5. Release the session pointer by calling the session's IUnknown::Release method.
  6. If you called OleInitialize during session startup to initialize the OLE libraries, uninitialize them now by calling OleUninitialize. Only clients that have called OleInitialize must call OleUninitialize.
  7. Uninitialize the MAPI libraries by calling MAPIUninitialize. If you called OleInitialize at some point, make sure that a call to OleUninitialize occurs before this call to MAPIUninitialize. The timing is crucial. If the call to OleUninitialize follows the call to MAPIUninitialize, your client might terminate ungracefully.
  8. If you called ScInitMapiUtil during session startup to initialize the MAPI utility library, uninitialize it now by calling DeinitMapiUtil. Only clients that have called ScInitMapiUtil must call DeinitMapiUtil.

Note All open objects must be released before the call to IMAPISession::Logoff. Objects that remain open after Logoff is called become invalid, they cannot accept any calls and might never be freed. If a call is made to one of these objects, expect the call to fail.

When a MAPI session ends, all of the service provider DLLs are unloaded. They are not deleted. MAPI has no mechanism for deleting DLLs during the session shutdown process. A service provider's DLL can only be deleted when a configuration client such as the Control Panel calls its message service entry point function with the MSG_SERVICE_INSTALL event.

The MAPI spooler remains running as long as there is one client with an active session on the system. When the last client ends its session, the MAPI spooler is automatically shut down.


Using the Session to Access Objects

The session pointer that you receive from your call to MAPILogonEx can be used to access a wide variety of objects. The following table lists the methods that are used to access various objects:

Object | Session method
Profile section | OpenProfileSection
Message store | OpenMsgStore
Address book | OpenAddressBook
Message service administration object | AdminServices
Folder, message, address book container, distribution list, or messaging user | OpenEntry

With the OpenEntry method and a valid entry identifier, you can open any address book or message store provider object. There are other OpenEntry methods in MAPI, in addition to the IMAPISession method. OpenEntry is implemented in the following objects:

Object | Method
Address book provider's logon object | IABLogon::OpenEntry
Address book | IAddrBook::OpenEntry
Address book container | IMAPIContainer::OpenEntry
Session | IMAPISession::OpenEntry
Message store | IMsgStore::OpenEntry
Message store provider's logon object | IMSLogon::OpenEntry
Folder | IMAPIContainer::OpenEntry
Support object | IMAPISupport::OpenEntry

Some OpenEntry methods require an entry identifier of the object to be opened, as does IMAPISession::OpenEntry; other methods allow NULL to be specified. A NULL entry identifier is interpreted differently depending on the object. For example, when you call IAddrBook::OpenEntry with a NULL entry identifier, MAPI opens the root container of the address book. The message store's OpenEntry method behaves similarly; it opens the root folder of the message store. IMAPIContainer::OpenEntry, implemented by both folders and address book containers, might return MAPI_E_INVALID_PARAMETER or the root container, depending on the implementer.

In addition to disallowing a NULL value for the entry identifier, the session's OpenEntry method differs from other OpenEntry methods because its job is not to open objects. Instead, it examines the entry identifier and forwards the call to another OpenEntry method implemented by the appropriate service provider. For example, if you call IMAPISession::OpenEntry with the entry identifier of a message, MAPI calls the IMSLogon::OpenEntry method of the message store responsible for the message.

In addition to using the session to open objects, clients use it to compare them. The IMAPISession::CompareEntryIDs method compares objects by comparing their entry identifiers. If the MAPIUID structures contained within the entry identifiers belong to the same service provider, MAPI forwards the call to that provider. CompareEntryIDs returns an error value when the two entry identifiers do not match. Although this method can compare entry identifiers that belong to any type of object, CompareEntryIDs works best for higher level objects such as message stores and address book containers. To compare lower level objects, compare directly the objects' search keys (PR_SEARCH_KEY) or record keys (PR_RECORD_KEY).

Like OpenEntry, CompareEntryIDs is implemented by multiple objects. Choose which OpenEntry and CompareEntryID method to use according to the amount of information that you have about the object or objects to be opened or compared. Use the following guidelines when deciding which interface method to call:

  • If you have no information about the target objects, call IMAPISession::OpenEntry or IMAPISession::CompareEntryIDs. This approach enables access to any object, but is the slowest of the three.
  • If you know that the target objects are address book entries rather than, for example, folders, call the IAddrBook::OpenEntry or IAddrBook::CompareEntryIDs method. IAddrBook::OpenEntry opens the root container of the address book when NULL is specified as the target object. This approach enables access to any address book object and is faster than using IMAPISession, but slower than using IMAPIContainer.
  • If the entry identifier being used is a short-term entry identifier or if you know that the target objects belong to a particular address book container or folder, call the IMAPIContainer::OpenEntry method. This approach yields the fastest performance, but enables access only to objects in a specific container or folder.


Retrieving Primary and Provider Identity

Service providers, typically address book providers, have the option of supplying an identity that can be used to represent the session in a variety of situations. Three properties describe a provider's identity:

PR_IDENTITY_ENTRYID

PR_IDENTITY_DISPLAY

PR_IDENTITY_SEARCH_KEY

These properties are set to the entry identifier, display name, and search key of the corresponding identity object, which is typically a messaging user. Providers that supply an identity also set the STATUS_PRIMARY_IDENTITY flag in their PR_RESOURCE_FLAGS property.

Depending on your needs, you might use a particular provider's identity or the primary identity for the session. For example, you can use the primary identity to include it on printouts. You can use a provider's identity also for display purposes or to retrieve properties, such as PR_RESOURCE_PATH. PR_RESOURCE_PATH, if set, contains the path to files used or created by the provider. Retrieve the PR_RESOURCE_PATH property for the provider supplying the primary identity when you want to locate files that pertain to the user of the session.

To retrieve the identity of a specific provider
  1. Call IMAPISession::GetStatusTable to access the status table.
  2. Build a restriction using an SPropertyRestriction structure to match the PR_PROVIDER_DLL_NAME column with the name of the specified provider.
  3. Call IMAPITable::FindRow to locate the provider's row. The provider's identity will be stored in the PR_IDENTITY_ENTRYID column, if it exists.
To retrieve the primary identity for a session
  • Call IMAPISession::QueryIdentity.

    QueryIdentity bases session identity on the existence of the STATUS_PRIMARY_IDENTITY value in the PR_RESOURCE_FLAGS column for one of the rows in the status table. If none of the status rows have this value set, QueryIdentity assigns identity to the first service provider that sets the three PR_IDENTITY properties. If no service provider supplies an identity, QueryIdentity returns MAPI_W_NO_SERVICE. When this happens, you should create a character string to represent a generic user that can serve as the primary identity.

Note Do not call QueryIdentity during session start up; it will unnecessarily increase the amount of time it takes to start your session. This is because to access the status table and query for the PR_IDENTITY properties, the MAPI spooler must be available. The extra time it takes to start up the MAPI spooler will add to your start up time.

To explicitly set the primary identity for a session
  • Call IMsgServiceAdmin::SetPrimaryIdentity. Pass the MAPIUID for the target service provider.


Using the Status Table and Status Objects

MAPI provides a table with information about the status of the MAPI subsystem, MAPI spooler, address book, or a particular service provider. You can access this table by calling IMAPISession::GetStatusTable.

Each row in the status table represents a status object implemented by MAPI or a service provider. You can use a status object to display a provider's configuration property sheet, to change a provider password, to upload or download messages, and to communicate with a particular transport provider.

There are two ways to access a status object:

  • Through the status table
  • Through a logon object's OpenStatusEntry method

Because logon objects are unavailable to clients, you must use the status table to access status objects. The status table approach is indirect, requiring a few calls before the status object is opened and a pointer to its IMAPIStatus implementation returned.

To use the status table to open a status object
  1. Call IMAPIStatus::GetStatusTable to retrieve an IMAPITable pointer.
  2. Call the status table's IMAPITable::SetColumns method to limit the column set to PR_ENTRYID, PR_RESOURCE_TYPE, and PR_DISPLAY_NAME.
  3. Limit the table view to a particular status object. For MAPI implementations, a client can define a property restriction using PR_RESOURCE_TYPE. For service provider implementations, a client can restrict on PR_PROVIDER_DISPLAY, the name of the provider, or on PR_PROVIDER_DLL_NAME, the name of the provider DLL file.
  4. Call IMAPITable::Restrict to set the restriction.
  5. Call HrQueryAllRows, passing in the SPropertyRestriction structure, to retrieve the row that represents the status of the provider.
  6. Call IMAPISession::OpenEntry, specifying the entry identifier from the status table row, to open the status object and retrieve an IMAPIStatus pointer.

To display a property sheet, call the status object's IMAPIStatus::SettingsDialog method for the target provider. SettingsDialog displays a property sheet for viewing and in some cases, changing the configuration properties of a provider.

To communicate with a transport provider, call its status object's IMAPIStatus::ValidateState method. ValidateState can reconfigure a transport provider, prevent the provider from displaying a user interface, and control a session that involves downloading message headers from a remote server, depending on the flags that you pass in. For example, to cancel the downloading of remote headers, pass the ABORT_XP_HEADER_OPERATION flag to ValidateState. To connect or disconnect from the remote server, pass FORCE_XP_CONNECT or FORCE_XP_DISCONNECT. To reconfigure the provider, pass CONFIG_CHANGED.

Clients that implement sending or receiving of messages on demand call either a transport provider's or the MAPI spooler's IMAPIStatus::FlushQueues method. You can pass three flags into the method: FLUSH_UPLOAD, FLUSH_DOWNLOAD, and FLUSH_FORCE. FLUSH_UPLOAD instructs the provider or the MAPI spooler to send any messages waiting in the output queue while FLUSH_DOWNLOAD instructs the provider or the MAPI spooler to receive any incoming messages. FLUSH_FORCE can be set with either of the other flags to cause the status object to perform the flush regardless of the timing.

Do not expect to be able to call SettingsDialog or ChangePassword on any of the MAPI subsystem, MAPI spooler, or address book status objects. Both the subsystem and address book status objects only support ValidateState; the MAPI spooler status object supports FlushQueues in addition to ValidateState.

For more information, see Status Table and Status Objects.


Handling an Outgoing Message

An outgoing message is a message that can be sent to one or more recipients across one or more messaging systems or be posted to a folder in a message store.

To create and send an outgoing message
  1. Open the default message store. See Opening a Message Store and Opening the Default Message Store.
  2. Open the Outbox folder. See Opening a Folder.
  3. Call the Outbox folder's IMAPIFolder::CreateMessage method to create the new message.
  4. Create a recipient list with one or more resolved recipients. See Creating a Recipient List.
  5. Optionally, add a subject. See Creating a Message Subject.
  6. Add the message text. See Creating Message Text.
  7. If the message text is formatted, add rendering information. See Adding Rendering Information to Formatted Text.
  8. Optionally, add one or more attachments. See Creating a Message Attachment.
  9. Set other message properties as desired and then save and send the message by calling IMessage::SubmitMessage.
  10. Delete the sent message if the PR_DELETE_AFTER_SUBMIT property is set to TRUE or move it to the folder identified by the PR_SENTMAIL_ENTRYID property. See Processing a Sent Message.

If you want to intermittantly save the message before sending it, call the message's IMAPIProp::SaveChanges method. See Saving a Message or Sending a Message.

For more information about the role that message store providers, the MAPI spooler, and transport providers play in the message sending process, see Sending Messages with MAPI.


Creating a Recipient List

A recipient list is an ADRLIST structure that contains an array of property value structures for each message recipient — destination for the message. A recipient can represent a human user, a machine, or a folder. All messages to be sent require at least one recipient that has been through the name resolution process — a process for ensuring that the PR_ENTRYID property is included in the recipient's property value array.

The properties of a recipient are a combination of address book properties and message properties. Recipient properties can apply either to all messages for a particular recipient or only to the current message. Both message store and transport providers can set recipient properties.

Each recipient must have a core set of properties in its property value array by the time the message is ready to be sent. The required set of recipient properties include:

PR_ADDRTYPE

PR_DISPLAY_NAME

PR_EMAIL_ADDRESS

PR_ENTRYID

PR_OBJECT_TYPE

PR_SEARCH_KEY

These properties are used to access the recipient, send messages to it, and to compare it to others. Not all of these properties need to be available right away. You can add a recipient initially without knowing its entry identifier, relying on the name resolution process to assign this property. At some point before you send a message, call IAddrBook::ResolveName to make sure that all of the recipients in your recipient list are resolved. For more information about resolving recipients, see Resolving a Name.

Recipient lists can be created from messaging users or distribution list entries in an address book container or from one-offs. One-offs are recipients that are created either as temporary entries to be used only for addressing a single message or as entries to be added to a personal address book. The format for a one-off entry identifier and address is defined by MAPI. For information about these formats, see One-Off Addresses and One-Off Entry Identifiers.

You can allow users to build their recipient lists:

  • Only with entries from the address book.
  • Only with one-off entries.
  • With a combination of address book recipients and one-offs.
To create a recipient list using the common address dialog box
  1. Allocate an ADRPARM structure and a pointer to an ADRLIST structure.
  2. Zero the memory in the ADRPARM structure and set the ADRLIST pointer to NULL.
  3. Call IAddrBook::Address to display the address dialog box and populate the ADRPARM structure.
  4. Call IMessage::ModifyRecipients, passing the ADRLIST pointer. This structure will contain the properties of each of the recipients selected by the user.
To create a recipient list programmatically
  1. Allocate an ADRLIST structure that contains one ADRENTRY structure for each of the recipients to be included in the list. Make each ADRENTRY structure large enough to hold each of the required properties and PR_RECIPIENT_TYPE.
  2. For each recipient, set the property value array for its aEntries member in the ADRLIST structure. For example, the following code sample shows how to include the entry identifier and display name in the array.
LPADRLIST lpAdrList = NULL;

hr = MAPIAllocateBuffer(numProps * sizeof(SPropValue),
                (LPVOID FAR *(&lpAdrList->aEntries[0].rgPropVals);

lpAdrList->aEntries[0].rgPropVals[0].ulPropTag = PR_ENTRYID;
lpAdrList->aEntries[0].rgPropVals[0].Value.bin     = RecipEID;

lpAdrList->aEntries[0].rgPropVals[1].ulPropTag = PR_DISPLAY_NAME;
lpAdrList->aEntries[0].rgPropVals[1].Value.LPSZ     = szDisplay;

lpAdrList->aEntries[0].cValues=numProps;
  3. Call IMessage::ModifyRecipients with the MODRECIP_ADD flag set.


Creating a Message Subject

The subject of a message, PR_SUBJECT, is an optional property, used to summarize the intent of a message. If you choose to set it, make it a character string 128 bytes or less. The 128 byte limit is not a limit imposed by MAPI; it is a limit imposed by some message store providers. To ensure interoperability with providers that do impose it, limit subjects to 128 bytes.

Be aware that some message store providers do not allow PR_SUBJECT to be written to a stream with the IStream interface.

Do not set PR_SUBJECT_PREFIX; this property is set only on replies and forwarded messages.


Creating Message Text

Although some messages are made up of nothing more than a recipient list and a subject line, the content of most messages, specifically IPM.Note messages, includes text. Message text can be plain or formatted and is stored in two properties: PR_BODY and PR_RTF_COMPRESSED. If your client is plain text-based, set PR_BODY. If you support formatted text in the Rich Text Format (RTF), set either PR_RTF_COMPRESSED only or both PR_RTF_COMPRESSED and PR_BODY, depending on the message store provider that you are using. When an RTF-aware client is using an RTF-aware message store, it sets PR_RTF_COMPRESSED only. When an RTF-aware client is using a non-RTF-aware message store, it sets both properties.

Note Clients can use other types of formatted text in addition to RTF, but MAPI has not defined properties for managing types other than RTF.

To determine whether or not your message store supports Rich Text Format
  1. Call the message store's IMAPIProp::GetProps method to retrieve the PR_STORE_SUPPORT_MASK property.
  2. Check for the STORE_RTF_OK bit. If STORE_RTF_OK is set, the message store provider supports RTF text. If it is not set, the message store provider supports plain text only.
To set PR_RTF_COMPRESSED
  1. Call the message's IMAPIProp::OpenProperty method to open the PR_RTF_COMPRESSED property, specifying IID_IStream as the interface identifier and setting the MAPI_CREATE flag.
  2. Call the WrapCompressedRTFStream function, passing the STORE_UNCOMPRESSED_RTF flag if the STORE_UNCOMPRESSED_RTF bit is set in the message store's PR_STORE_SUPPORT_MASK property.
  3. Release the original stream by calling its IUnknown::Release method.
  4. Call either IStream::Write or IStream::CopyTo to write the message text to the stream returned from WrapCompressedRTFStream.
  5. Call the Commit and Release methods on the stream returned from the OpenProperty method.

At this point, if the message store provider supports RTF, you have done all that is required. You can depend on the message store provider to handle synchronizing the message content and formatting and to create the PR_BODY property if necessary. RTF-aware message stores call RTFSync to handle the synchronization. If the RTF_SYNC_BODY_CHANGED flag is set to TRUE, the provider will recompute the PR_BODY property.

If your message store provider does not support RTF, you must also add non-RTF message content by setting the PR_BODY property.

To set PR_BODY
  1. Call the IMAPIProp::OpenProperty method to open the PR_BODY property with the IStream interface.
  2. Call IStream::Write to write the message text data to the stream returned from OpenProperty.
  3. Call the RTFSync function to synchronize the text with the formatting. Because this is a new message, set both the RTF_SYNC_RTF_CHANGED and RTF_SYNC_BODY_CHANGED flags to indicate that both the RTF and plain text version of the message text has changed. RTFSync will set several related properties that the message store provider requires, such as PR_RTF_IN_SYNC, and write them to the message.
  4. Call IStream::Commit and IUnknown::Release on the stream to commit the changes and free its memory.


Adding Rendering Information to Formatted Text

To indicate where in formatted text an attachment is to be rendered, you must insert a sequence of placeholder characters in the message's PR_RTF_COMPRESSED property. The placeholder sequence is made up of the following characters:

\objattph
To add rendering information to formatted message text
  • When writing the stream of text to the message's PR_RTF_COMPRESSED property, insert the placeholder sequence and a space character at the position where the attachment should be rendered.
  • Set the PR_RENDERING_POSITION property of each attachment to a numeric value. The lowest value should be assigned to the PR_RENDERING_POSITION property of the first attachment to appear in the formatted text; the highest value to the last attachment.


Creating a Message Attachment

A message attachment is some additional data, such as a file, another message, or an OLE object, that you can send or save along with a message. Each attachment has a collection of properties that identifies it and describes its type and how it is rendered. Like recipients, message attachments can only be accessed through the message to which they belong. Therefore, for an attachment to be usable, its message must be open.

To create a message attachment
  1. Call the message's IMessage::CreateAttach method and pass NULL as the interface identifier. CreateAttach returns a number that uniquely identifies the new attachment within the message. The attachment number is stored in the PR_ATTACH_NUM property and is valid only as long as the message containing the attachment is open.
  2. Call IMAPIProp::SetProps to set PR_ATTACH_METHOD to indicate how to access the attachment. PR_ATTACH_METHOD is required. Set it to:
    • ATTACH_BY_VALUE if the attachment is binary data.
    • ATTACH_BY_REFERENCE, ATTACH_BY_REF_RESOLVE, or ATTACH_BY_REF_ONLY if the attachment is a file.
    • ATTACH_EMBEDDED_MSG if the attachment is a message.
    • ATTACH_OLE if the attachment is an OLE object.
  3. Set the appropriate attachment data property:
    • PR_ATTACH_DATA_BIN for binary data and OLE 1 objects.
    • PR_ATTACH_PATHNAME for files.
    • PR_ATTACH_DATA_OBJ for messages and OLE 2 objects.
  4. Set PR_ATTACH_RENDERING to hold the graphic representation of the attachment for file or binary attachments. Do not set it for OLE objects, which store the rendering information internally, or for attached messages.
  5. Set PR_RENDERING_POSITION to indicate where the attachment should be displayed. PR_RENDERING_POSITION applies only to clients that set the PR_BODY property. If you only support PR_RTF_COMPRESSED, place the following placeholder information in the compressed stream:
    \objattph

    To set PR_RENDERING_POSITION, assign either a number that represents an ordinal offset in characters, with the first character of PR_BODY being 0, if you need to know where in the message the attachment is rendered, or 0xFFFFFFFF, if you do not render attachments within PR_BODY.

  6. Set PR_ATTACH_FILENAME to indicate the short name of the file for a file attachment and PR_ATTACH_LONG_FILENAME to indicate the name of the file as supported on a platform that handles the long filename format. Both properties are optional. However, if you set PR_ATTACH_LONG_FILENAME, also set PR_ATTACH_FILENAME.
  7. Set PR_DISPLAY_NAME to indicate the name for the attachment that can appear in a dialog box. PR_DISPLAY_NAME is optional.
To set PR_ATTACH_DATA_BIN
  1. Call IMAPIProp::OpenProperty to open the property with the IStream interface.
  2. If a file contains the data and it is open or if you need explicit control over buffer size, call IStream::Write in a loop to place the data in the stream.
  3. Another option is to call OpenStreamOnFile to create a stream to access the data file and then call this stream's IStream::CopyTo method to copy the data to the stream returned by OpenProperty.
  4. Call the new stream's IStream::Commit method.
To set PR_ATTACH_DATA_OBJ
  1. Call IMAPIProp::OpenProperty to open the property with the IStreamDocfile interface to create a stream that works with structured storage. IStreamDocfile is implemented by message store providers to give clients a higher-performance way to store and retrieve structured storage. The IStreamDocfile interface is the same as IStream, but the content of the stream is guaranteed to be formatted as structured storage. If this call succeeds, create the stream with the same steps outlined for setting PR_ATTACH_DATA_BIN.
  2. If OpenProperty fails:
    1. Call OpenProperty again asking for IStorage.
    2. Call StgOpenStorage to open the OLE object and return a storage object.
    3. Call the returned storage object's IStorage::CopyTo method to copy to the storage object returned from OpenProperty.
    4. Call the new storage object's IStorage::Commit method.
To set PR_ATTACH_PATHNAME
  1. Allocate an SPropValue structure, setting the ulPropTag member to PR_ATTACH_PATHNAME and the Value.LPSZ member to the character string that represents the filename.
  2. Call the attachment's IMAPIProp::SetProps method.

Note If your platform supports long filenames, set both PR_ATTACH_PATHNAME and PR_ATTACH_LONG_PATHNAME. It might be necessary to make an operating system call to retrieve the short filename.

For more information, see Attachments.


Saving a Message

Before a message is saved, clients typically call the message's IMAPIProp::SetProps method to set a few properties in addition to the message text properties, attachment properties, PR_SUBJECT, and properties associated with the recipient list.

Set the PR_MESSAGE_CLASS property to a character string such as IPM.Note that describes the class of the outgoing message. Although clients should set PR_MESSAGE_CLASS on all outgoing messages, a default value is supplied by the message store provider if you do not set it. The default message class for outgoing messages is IPM.

Set the MSGFLAG_UNSENT flag in the PR_MESSAGE_FLAGS property. If desired, also set the MSGFLAG_READ and MSGFLAG_UNMODIFIED flags. Setting the MSGFLAG_UNMODIFIED allows a message under composition to simulate a delivered message. MSGFLAG_UNMODIFIED can only be set by clients before a message has been saved for the first time.

If you implement scheduling as a feature, set these properties on your message:

PR_START_DATE

PR_END_DATE

PR_OWNER_APPT_ID

The PR_START_DATE and PR_END_DATE properties mark the beginning and end of an appointment, respectively.

The PR_OWNER_APPT_ID property contains an identifier that represents an appointment and can be used to schedule meetings. This identifier is an integer rather than an entry identifier.

When you are ready to make a permanent copy of an unsent message, call IMAPIProp::SaveChanges on the message and all of its attachments. If you intend to send the message right away, you do not need to call SaveChanges. The call to SubmitMessage internally saves the message as part of its processing.

When calling SaveChanges, it is a good idea to specify the KEEP_OPEN_READWRITE flag, which allows the message to be modified at a later time. Other settable flags include FORCE_SAVE, which indicates that the message or attachment should be closed after changes are committed, KEEP_OPEN_READONLY, which indicates that no further changes will be made, and the flag to allow the message store provider to batch client requests, MAPI_DEFERRED_ERRORS.

It is essential that you call SaveChanges for every attachment in the message before you call SaveChanges for the message. If you fail to save an attachment, the attachment will not be included with the message when it is sent and it will not appear in the message's attachment table. If you fail to save the message after saving all of the attachments, both the message and the attachments will be lost.

When SaveChanges is called, the message store provider updates the following properties:

  • PR_DISPLAY_TO lists all primary recipients.
  • PR_DISPLAY_CC lists all carbon copy recipients.
  • PR_DISPLAY_BCC lists all blind carbon copy recipients.
  • PR_LAST_MODIFICATION_TIME
  • PR_MESSAGE_FLAGS sets MSGFLAG_HASATTACH if one or more attachments have been saved and clears MSGFLAG_UNMODIFIED to show the message has changed.
  • PR_MESSAGE_SIZE contains the most current size of the message.
  • PR_MESSAGE_ATTACHMENTS provides access to the attachment table.
  • PR_MESSAGE_RECIPIENTS provides access to the recipient table.

Some message properties are typically supplied by clients or service providers when a message is created. If a client neglects to set them, it is up to the message store provider to update them at the time SaveChanges is called. For example, if a message's PR_ENTRYID and PR_RECORD_KEY properties were set when the message was created, they need not be modified at save time. However, message store providers that neglect to set them at message creation must set them the first time that SaveChanges is called.

If SaveChanges returns MAPI_E_CORRUPT_DATA, assume that the data being saved is now lost. Message store providers that use a client-server model for their implementation might return this value when a network connection is lost or the server is not running. Before returning an error to the user, try to write and save the data a second time by making a call to SetProps followed by another call to SaveChanges. If the data is cached locally, this should not be a problem. However, if there is no local cache or the second SaveChanges call fails, display an error to alert the user to the problem.


Sending a Message

When you are ready to send a message, call its IMessage::SubmitMessage method. SubmitMessage places the message in the outgoing queue and sets the MSGFLAG_SUBMIT flag in the message's PR_MESSAGE_FLAGS property. The message store provider, if tightly coupled to a transport provider, gives the message directly to the transport which delivers it to the messaging system. If not tightly coupled, the message store provider informs the MAPI spooler that the outgoing queue has changed and the MAPI spooler transfers the message to an appropriate transport provider.

If you allow users to cancel a send operation, call IMsgStore::AbortSubmit to implement this feature. AbortSubmit removes the message from the outgoing queue. Users can be allowed to stop a send from happening until the message is given to the underlying messaging system.

If SubmitMessage returns MAPI_E_CORRUPT_DATA, assume that the data being sent is now lost. Before attempting to send a second time, re-write the message by calling SetProps and SaveChanges. Display an error to the user if these IMAPIProp calls fail or if SubmitMessage fails a second time.

After a successful call to SubmitMessage, free any memory that was allocated for the recipient list and release the message and its attachments. Once a message has been sent, MAPI does not permit any further operations on the pointers for these objects. The one exception is calling IUnknown::Release. No other calls are allowed because many message store providers invalidate entry identifiers for messages that have been sent.


Processing a Sent Message

Outgoing messages, after they have been sent, can be left in the Outbox folder, moved to a folder designated to hold sent messages, or deleted. The type of processing depends on whether or not you have set the message store properties:

PR_DELETE_AFTER_SUBMIT

PR_SENTMAIL_ENTRYID

PR_DELETE_AFTER_SUBMIT is a Boolean property, set to TRUE if messages should be deleted after they are sent, and FALSE otherwise. PR_SENTMAIL_ENTRYID is the entry identifier of a folder. When this property is set, you should move sent messages to the folder represented by this entry identifier. The saved messages typically have the identity of the last message store or transport provider to send them.

Any combination of these properties can be set — both, neither, or one or the other. However, if you set PR_SENTMAIL_ENTRYID, it must contain a valid entry identifier.

The following table describes how these properties affect what you do with sent messages.

If neither property is set: | Leave the message in the folder from which it was sent (typically the Outbox).
If both properties are set: | Move the message to the indicated folder, if desired, and then delete it.
If PR_SENTMAIL_ENTRYID is set: | Move the message to the indicated folder.
If PR_DELETE_AFTER_SUBMIT is set: | Delete the message.


Posting a Message

Posting a message is similar to sending a message. The main difference is the destination. Rather than being directed to one or more recipients across one or more messaging systems, a posted message remains in a folder in the current message store.

To post a message
  1. Open the destination folder by calling IMsgStore::OpenEntry. If the destination folder is the Inbox, locate the entry identifier to pass to OpenEntry by calling IMsgStore::GetReceiveFolder.
  2. Call IMAPIFolder::CreateMessage to create the message.
  3. Call the message's IMAPIProp::SetProps method to set:
    • The MSGFLAG_UNSENT flag in the PR_MESSAGE_FLAGS property.
    • The PR_SENDER properties.
    • The PR_SENT_REPRESENTING properties.
    • The PR_RECEIPT_TIME property.
    • The PR_RTF_COMPRESSED or PR_BODY property.
    • The PR_SUBJECT property.
  4. Call the message's IMAPIProp::SaveChanges method to save the message.
  5. If necessary, create an attachment, set its properties, and save it. For detailed information about adding attachments to messages, see Creating a Message Attachment.
  6. Call IMessage::SaveChanges to save the message. At this point it will appear in the contents table of the Inbox.

Notice that you do not create a recipient list. Instead, you set several properties that are normally set by a transport provider for a sent message.

If you want to save a message intermittantly before having it appear in the contents table of the Inbox, create it instead in a hidden folder such as the root folder of the IPM subtree and then move it to the Inbox.


Resending an Undelivered Message

A transport provider sends a nondelivery report (NDR) when it cannot successfully deliver a message that you have submitted. It is up to the client whether or not users can attempt to resend these undelivered messages. If you support resending messages, you can either use a form provided by MAPI or implement your own. The MAPI form displays the names of the failed recipients and the reason for the delivery failure, if possible, and includes a button that, when selected, allows a user to resend the message.

When a resent message is received, it should look exactly like the original message. The recipient should be unable to differentiate between a message that was delivered on its first attempt at transmission or a subsequent attempt. Replies on this message should work exactly as if the message had been sent successfully the first time.

To resend an undelivered message
  1. Call IMAPIFolder::CreateMessage to create a new message.
  2. Copy all of the properties from the original message, excluding PR_MESSAGE_RECIPIENTS, the PR_SENDER properties, and the PR_SENT_REPRESENTING properties. Make the following property modifications:
    • Set PR_MESSAGE_CLASS to the report's PR_ORIG_MESSAGE_CLASS property.
    • Set the MSGSTATUS_RESEND flag in the PR_MESSAGE_FLAGS property.
    • Set PR_ORIGINAL_ENTRYID to the original message's PR_ENTRYID property.
    • For each recipient, set MAPI_SUBMITTED in the PR_RECIPIENT_TYPE property.
    • Duplicate each failed recipient. Change the PR_RECIPIENT_TYPE property for the duplicated recipient to MAPI_P1. Therefore, for each failed recipient there are now two entries in the recipient table: one with PR_RECIPIENT_TYPE set to its original value and the other with PR_RECIPIENT_TYPE set to MAPI_P1.
  3. Call ScCreateConversationIndex to set up conversation tracking if desired.
  4. Call the new message's IMessage::ModifyRecipients method to update the recipient list.
  5. Call IMessage::SubmitMessage to save and send the new message.


Sending a Reply

Client applications typically support two types of replies: one that is sent only to the sender of the original message and one that is sent to all other recipients included in the recipient list of the original message in addition to the sender. This second type of reply is commonly referred to as a reply all message.

To send a reply of either type, you implement some of the same tasks that you would when you send an original message. For example, you open the default message store and the outgoing message folder, typically the Outbox, and call the outgoing folder's IMAPIFolder::CreateMessage method to create the reply. Also, you open the folder that holds the original message, typically the Inbox. For information about opening different folders, see Opening a Folder.

The main difference between creating a reply and creating an original message is that with a reply, most of the properties are either based on or copied directly from properties of the original message. Attachments — a message's PR_MESSAGE_ATTACHMENTS property — are specifically excluded. The recipient list for a reply all message is created from the original message's list with the recipient represented by the PR_RECEIVED_BY_SEARCH_KEY property and all blind carbon copy recipients removed. The PR_RECEIVED_BY_SEARCH_KEY property represents the current user.

To send a reply
  1. Open the default message store. See Opening the Default Message Store.
  2. Open the Outbox folder. See Opening a Folder.
  3. Call the Outbox's IMAPIFolder::CreateMessage method to create the reply.
  4. Call the original message's IMAPIProp::CopyTo method to copy the following properties to the reply message:
    • PR_BODY or PR_RTF_COMPRESSED, depending on whether or not you support Rich Text Format.
    • PR_MESSAGE_RECIPIENTS, if the reply will go to the entire recipient list.
    • PR_NORMALIZED_SUBJECT.
  5. Do not include the following properties in your call to IMAPIProp::CopyTo:

PR_CLIENT_SUBMIT_TIME | PR_MESSAGE_DELIVERY_TIME
PR_MESSAGE_DOWNLOAD_TIME | PR_MESSAGE_FLAGS
PR_ORIGINATOR_DELIVERY_ REPORT_REQUESTED | PR_RCVD_REPRESENTING properties
PR_READ_RECEIPT_ENTRYID | PR_READ_RECEIPT_REQUESTED
PR_RECEIVED_BY properties | PR_REPLY_RECIPIENT properties
PR_REPORT_ENTRYID | PR_SENDER properties
PR_SENT_REPRESENTING properties | PR_SENTMAIL_ENTRYID
PR_SUBJECT_PREFIX |

  6.
Add separator text to whichever message body property you support — PR_BODY or PR_RTF_COMPRESSED.
    7.

  7.
Call ScCreateConversationIndex, passing in the value of the original message's PR_CONVERSATION_INDEX property.
    8.

  8.
Set a prefix for the reply. If you are using the standard "RE:", concatenate these characters onto the beginning of PR_NORMALIZED_SUBJECT and set PR_SUBJECT to this new string. Do not set PR_SUBJECT_PREFIX. If you are using a nonstandard prefix, such as a string longer than three characters, store it in PR_SUBJECT_PREFIX.
    9.

  9.
Set the PR_SENT_REPRESENTING properties to the corresponding values in the PR_RCVD_REPRESENTING properties.
    10.

  10.
Set each of the entries in PR_REPLY_RECIPIENT_ENTRIES and PR_REPLY_RECIPIENT_NAMES to the entry identifier and display name of a primary recipient — a recipient whose type is MAPI_TO.

Keep these properties synchronized. That is, PR_REPLY_RECIPIENT_ENTRIES and PR_REPLY_RECIPIENT_NAMES must contain the same number of entries, and an entry at a particular position in one of the properties must correspond to an entry at the same position in the other property.

    11.

  11.
If the reply is being sent only to the sender of the original message, create a single entry recipient list with the recipient represented by the original message's PR_SENT_REPRESENTING property. For more information about creating a recipient list, see Creating a Recipient List.
    12.

  12.
If the reply is a reply all, create a recipient list as follows:

    1.
Call the original message's IMessage::GetRecipientTable method to access its recipient table.
      2.

    2.
Call HrQueryAllRows to retrieve all of the rows in the table. Determine if each row represents a primary or carbon copy recipient and should remain in the list or if it represents a blind carbon copy recipient or the user and should be removed from the list.
      3.

    3.
Differentiate between recipient types by looking at the PR_RECIPIENT_TYPE column. This column will be set to MAPI_TO for primary recipients, MAPI_CC for carbon copy recipients, and MAPI_BCC for blind carbon copy recipients.
      4.

    4.
Compare the PR_SEARCH_KEY column with the PR_RECEIVED_BY_SEARCH_KEY property of the original message to determine if the row represents the user.
      5.

    5.
Remove unwanted rows from the recipient list by calling MAPIFreeBuffer to free the memory associated with the corresponding entries in the recipient table's SRowSet structure. Set all of the values in the property value array to zero, all of the cValues members to zero, and all of the lpProps members in each SRow structure in the SRowSet to NULL.
      6.

    6.
Add the sender to the recipient list, as represented by the original message's PR_SENT_REPRESENTING_NAME and PR_SENT_REPRESENTING_ENTRYID properties. Check that the sender is not duplicated in the list.
      7.

    7.
Call the reply message's IMessage::ModifyRecipients method, setting the ulFlags parameter to zero, to create a new recipient list for the reply or forwarded message based on the list from the original message.
      8.

    13.

  13.
Call the reply's IMAPIProp::SaveChanges method to save the message or IMessage::SubmitMessage to save and send it.
    14.

Note  Before calling IMessage::ModifyRecipients to store changes in the recipient list, you can allow users to make modifications through the message form. Users can add to the list or remove particular members. Allowing users to make changes to a recipient list is an optional client feature.


Forwarding a Message

Forwarding a message involves many of the same tasks as sending an original message. First, you must open the default message store and the folder that is designated to hold outgoing messages, typically the Outbox, and call this folder's IMAPIFolder::CreateMessage method to create the message to be forwarded. You must also open the folder that holds the original message, typically the Inbox. For information about opening different folders, see Opening a Folder.

The main difference between creating a message to be forwarded and creating the original is that with a forwarded message, most of the properties are either based on or copied directly from properties of the original message.

To forward a message
  1. Open the default message store. See Opening the Default Message Store.
  2. Open the Outbox folder. See Opening a Folder.
  3. Call the Outbox's IMAPIFolder::CreateMessage method to create a new forwarded message.
  4. Call the original message's IMAPIProp::CopyTo method to copy the following properties to the forwarded message:
    • PR_BODY or PR_RTF_COMPRESSED, depending on whether or not you support Rich Text Format.
    • PR_NORMALIZED_SUBJECT
  5. Copy the message attachments from the original message either by calling the original message's IMAPIProp::CopyTo method to copy the PR_MESSAGE_ATTACHMENTS property or by invoking the following three step procedure for each attachment to be copied:
    1. Call the new forwarded message's IMessage::CreateAttach method to create a new attachment.
    2. Call the original message's IMessage::OpenAttach method to open the attachment to be copied.
    3. Call the original message's IMAPIProp::CopyTo method to copy all of the attachment properties from the old attachment to the new one.
  6. Do not include the following properties in your call to IMAPIProp::CopyTo:

PR_CLIENT_SUBMIT_TIME | PR_MESSAGE_DELIVERY_TIME
PR_MESSAGE_DOWNLOAD_ TIME | PR_MESSAGE_FLAGS
PR_ORIGINATOR_DELIVERY_ REPORT_REQUESTED | PR_RCVD_REPRESENTING properties
PR_READ_RECEIPT_ENTRYID | PR_READ_RECEIPT_REQUESTED
PR_RECEIVED_BY properties | PR_REPLY_RECIPIENT properties
PR_REPORT_ENTRYID | PR_SENDER properties
PR_SENT_REPRESENTING properties | PR_SENTMAIL_ENTRYID
PR_SUBJECT_PREFIX |

  7.
Format the message text by adding indentation and a header paragraph that includes the original sender, date of transmission, subject, and recipient list. Do not include Internet-style prefix characters with the content.
    8.

  8.
Call ScCreateConversationIndex, passing in the value of the original message's PR_CONVERSATION_INDEX property.
    9.

  9.
Set a prefix for the forwarded message. If you are using the standard "FW:", concatenate these characters onto the beginning of PR_NORMALIZED_SUBJECT and set PR_SUBJECT to this new string. Do not set PR_SUBJECT_PREFIX. If you are using a nonstandard prefix, such as a string longer than three characters, store it in PR_SUBJECT_PREFIX.
    10.

  10.
Set the PR_SENT_REPRESENTING properties to the corresponding values in the PR_RCVD_REPRESENTING properties.
    11.

  11.
Create a recipient list. See Creating a Recipient List.
    12.

  12.
Call the forwarded message's IMAPIProp::SaveChanges method to save it or IMessage::SubmitMessage to save and send it.
    13.


Handling an Incoming Message

An incoming message is a message that has been sent across one or more messaging systems. It may have been sent only to you or to many other recipients. Incoming messages are placed in a receive folder designated to hold messages of a particular class. You can set up a different receive folder for each message class that you handle or use one folder for all of the classes.

If you have registered for new mail notifications with the message store, you will be notified whenever a message is placed in a receive folder. If you have not registered for new mail notifications, you must open the appropriate receive folder periodically to manually check for the arrival of new messages.

Clients register for new mail notifications by setting the parameters to IMsgStore::Advise as follows:

  • Set cbEntryID to 0.
  • Set lpEntryID to NULL.
  • Set ulEventMask to fnevNewMail.

The lpNotifications parameter in the call to your IMAPIAdviseSink::OnNotify method points to a NEWMAIL_NOTIFICATION structure that contains information about the incoming message, such as its message class, its entry identifier, the entry identifier of its parent folder, and the contents of its PR_MESSAGE_FLAGS property. For more information about registering for and handling notifications, see Handling Notifications.

Before displaying an incoming message to a user, determine if its message class is a class that your client supports. If not, ignore the message. If the class is one that you support, you can open and display the message with a form that is appropriate for the message class of the message. The choice of forms is based on message class. Messages that belong to the IPM class use a default form implemented by MAPI. Messages that belong to custom classes defined by clients can use either client-defined specialized forms or the MAPI default form.

To open and display an incoming message
  1. Call IMsgStore::GetReceiveFolder to retrieve the entry identifier of the receive folder for the message class of the message and pass this entry identifier to IMsgStore::OpenEntry to open the folder. See Opening a Folder for more information.
  2. Call the receive folder's IMAPIContainer::GetContentsTable method to retrieve its contents table. Call the table's IMAPITable::QueryRows method to retrieve all the rows in the table. For more information about contents tables in general, see Contents Tables. For more information about displaying a contents table, see Displaying a Folder Contents Table.
  3. If your client is interactive, allow the user to select a message from the table and determine the form to be used to display that message. Clients can use the default form provided by MAPI or a custom form. For more information, see Handling MAPI Forms.
  4. Call IMsgStore::OpenEntry to open the message. For more information, see Opening a Message.
  5. Process the message text. See Opening Message Text.
  6. Render each of the message attachments. See Rendering an Attachment in Plain Text or Rendering an Attachment in Formatted Text.
  7. Open an attachment if desired. See Opening an Attachment.


Opening Message Text

The text of a message is stored either in its PR_BODY property or PR_RTF_COMPRESSED property. If you support the Rich Text Format (RTF), open PR_RTF_COMPRESSED. If you do not support RTF, open PR_BODY. Because the text of a message can be large regardless of whether or not it is formatted, use IMAPIProp::OpenProperty to open these properties.

To display formatted message text
  1. If you are using a non-RTF aware message store, as indicated by the absence of the STORE_RTF_OK flag in the store's PR_STORE_SUPPORT_MASK property:
    1. Call the message's IMAPIProp::GetProps method to retrieve the PR_RTF_IN_SYNC property.
    2. Call RTFSync to synchronize the message's PR_BODY property with the PR_RTF_COMPRESSED property. Pass the RTF_SYNC_BODY_CHANGED flag if the call to retrieve PR_RTF_IN_SYNC failed because the property does not exist or it is set to FALSE.
    3. If RTFSync returned TRUE — indicating that changes were made — call the message's IMAPIProp::SaveChanges method to permanently store them.
  2. Regardless of whether or not you are using an RTF-aware message store:
    1. Call IMAPIProp::OpenProperty to open the PR_RTF_COMPRESSED property.
    2. If PR_RTF_COMPRESSED is not available, call OpenProperty to open the PR_BODY property.
    3. Call the WrapCompressedRTFStream function to create an uncompressed version of the compressed RTF data, if available.
    4. Copy the formatted text from the stream to the appropriate place in the message form.
To display plain message text
  1. Call the message's IMAPIProp::GetProps method to retrieve the PR_BODY property.
  2. If GetProps returns either PT_ERROR for the property type in the property value structure or MAPI_E_NOT_ENOUGH_MEMORY, call the message's IMAPIProp::OpenProperty method. Pass PR_BODY as the property tag and IID_IStream as the interface identifier.
  3. Copy the plain text from the stream to the appropriate place in the message form.


Rendering an Attachment in Plain Text

To render an attachment in a message with plain text, retrieve the attachment's PR_RENDERING_POSITION property and apply it to the data in the PR_ATTACH_RENDERING property. There are two ways to retrieve PR_RENDERING_POSITION:

  • Open the attachment by calling the message's IMessage::OpenAttach method and then ask for the PR_RENDERING_POSITION property by calling the attachment's IMAPIProp::GetProps method.
  • Call the message's IMessage::GetAttachmentTable method to access its attachment table and retrieve the column that holds the PR_RENDERING_POSITION property. This way is always preferable.

Keep in mind that many RTF-aware message stores do not calculate PR_RENDERING_POSITION until a client requests the PR_BODY property of a message. Until that time, PR_RENDERING_POSITION usually represents an approximate value. Message store providers are allowed to supply clients with an approximate value to enhance performance.

The rendering for a file or binary attachment is stored in its PR_ATTACH_RENDERING property. You have the choice of retrieving PR_ATTACH_RENDERING in the same ways as you retrieved PR_RENDERING_POSITION: directly from the attachment or from the attachment table. For PR_ATTACH_RENDERING, the first strategy, although more time-consuming, is safer. Because some message store providers truncate their table columns to 255 bytes, or in a few cases 510 bytes, it is difficult to be sure that the PR_ATTACH_RENDERING column contains the complete rendering. When retrieving the property directly from the attachment, it will always be complete.

Neither OLE nor message attachments set PR_ATTACH_RENDERING. Instead, rendering information for OLE 1 attachments is stored in the message text stream. For OLE 2 attachments, it is stored in a special child stream of the storage object. Rendering information for message attachments is available through the form manager.

To retrieve the rendering for a message attachment
  1. Use the message class of the message to access the form manager.
  2. Access the form manager's PR_MINI_ICON property.


Rendering an Attachment in Formatted Text

Rich Text Format (RTF)-aware clients can retrieve rendering position information from RTF message text by looking for the following escape sequence in the message's PR_RTF_COMPRESSED property:

\objattph
To locate rendering information in formatted text
  1. Call IMessage::GetAttachmentTable to access the message's attachment table.
  2. Build a property restriction that limits the table to rows that have PR_RENDERING_POSITION not equal to -1.
  3. Call IMAPITable::Restrict to enforce the restriction.
  4. Call IMAPITable::SortTable to sort the attachments.
  5. Call IMAPITable::QueryRows to retrieve the appropriate rows.
  6. Call the message's IMAPIProp::OpenProperty method to retrieve PR_RTF_COMPRESSED with the IStream interface.
  7. Scan the stream, looking for the rendering placeholder, \objattph. The character following this placeholder is the place for the next attachment in the sorted table.


Opening an Attachment

Opening an attachment involves displaying its data. For example, when a file attachment is opened, the contents of the file are displayed. Whereas messages and folders are opened using their entry identifiers, attachments are opened using their attachment numbers — PR_ATTACH_NUM properties. Attachment numbers are available through a message's attachment table.

To open all attachments in a message
  1. Call the message's IMessage::GetAttachmentTable method to access its attachment table.
  2. Call HrQueryAllRows to retrieve all the rows in the table.
  3. For each row:
    1. Open the attachment by passing the attachment number represented in the PR_ATTACH_NUM column in a call to the message's IMessage::OpenAttach method. OpenAttach returns a pointer to an IAttach implementation that provides access to attachment properties.
    2. Call the attachment's IMAPIProp::GetProps method to retrieve its PR_ATTACH_METHOD property.
    3. If PR_ATTACH_METHOD is set to ATTACH_BY_REF_ONLY, call IMAPIProp::GetProps to retrieve the PR_ATTACH_PATHNAME property.
    4. If PR_ATTACH_METHOD is set to ATTACH_BY_VALUE, call IMAPIProp::OpenProperty to open the PR_ATTACH_DATA_BIN property with the IStream interface. See the sample code following this procedure.
    5. If PR_ATTACH_METHOD is set to ATTACH_OLE and the attachment is an OLE 2 object:
1. Call IMAPIProp::OpenProperty to open the PR_ATTACH_DATA_OBJ property with the IStreamDocfile interface. Attempt to use this interface because it is an implementation of IStream guaranteed to work with structured storage with the least amount of overhead.
2. If the OpenProperty call fails, call it again to retrieve the PR_ATTACH_DATA_BIN property with the IStreamDocfile interface.
3. If this second OpenProperty call fails, try again to call OpenProperty to retrieve PR_ATTACH_DATA_OBJ. However, rather than specifying IStreamDocfile, specify the IStorage interface.

  6. If PR_ATTACH_METHOD is set to ATTACH_EMBEDDED_MSG, it is not unusual for the value of PR_ATTACH_DATA_OBJ to contain an error. This is because you and the table implementer have no way to agree on the type of object to return. To retrieve a pointer to the attached message, open the attachment using IMessage::OpenAttach. Then access the attachment data by calling its IMAPIProp::OpenProperty method.

You can request that an attachment is opened in read/write or read-only mode. Read-only is the default mode, and many message store providers open all attachments in this mode regardless of what clients request. Pass the MAPI_BEST_ACCESS flag to request that the message store provider grant the highest level of access it can and then retrieve the open attachment's PR_ACCESS_LEVEL property to determine the level of access that was actually granted.

The following example shows how to open the data in an attachment's PR_ATTACH_DATA_BIN property. It allocates pointers to two streams: one for the file and one for the attachment. The OpenStreamOnFile function opens the file stream in read-only mode. The call to the attachment's IMAPIProp::OpenProperty method opens the attachment stream in read/write mode. The code then copies from the file stream to the attachment stream and releases both streams.

LPSTREAM pStreamFile, pStreamAtt;
HRESULT hr;

hr = OpenStreamOnFile (MAPIAllocateBuffer, MAPIFreeBuffer,
                       STGM_READ, "myfile.doc", NULL, &pStreamFile);
if (HR_SUCCEEDED(hr))
{
    // Open the destination stream in the attachment object
    hr = pAttach->OpenProperty (PR_ATTACH_DATA_BIN,
                                &IID_IStream,
                                0,
                                MAPI_MODIFY | MAPI_CREATE,
                                (LPUNKNOWN *)&pStreamAtt);
    if (HR_SUCCEEDED(hr))
    {
        STATSTG StatInfo;
        pStreamFile->Stat (&StatInfo, STATFLAG_NONAME);
        hResult = pStreamFile->CopyTo (pStreamAtt, StatInfo.cbSize,
                                       NULL, NULL);
        pStreamAtt->Release();
    }
    pStreamFile->Release();
}


Handling a Message Store

Handling a message store is an important part of any client's set of tasks. These tasks include opening, copying, moving, adding, and deleting folders and messages, displaying various tables, setting properties, and controlling access levels.


Opening a Message Store

Depending on the profile, a client will need to open one or more message stores during a typical session. Opening a message store means gaining access to a pointer to its IMsgStore implementation. The IMsgStore interface provides methods for notification, making folder assignments, and accessing folders and messages.

Clients open message stores at logon and when a profile is being modified. If your client allows users to add message stores to the profile during an active session, you can either open them immediately or ignore them until the next session. By registering for notifications on the message store table, you will be alerted to the availability of a new message store.

To open a message store, you must have its entry identifier available. Most clients access the entry identifiers for the message stores they wish to open through the message store table. However, some message stores document the format of their entry identifiers, thereby allowing clients to bypass the message store table and construct the necessary entry identifier. They can pass this entry identifier directly to IMAPISession::OpenMsgStore and MAPI automatically creates a profile section for the provider without associating it with any message service.

To retrieve an entry identifier from the message store table
  1. Call IMAPISession::GetMsgStoresTable to open the message store table.
  2. Call IMAPITable::SetColumns to limit the table to a small column set that includes the following columns:

    PR_PROVIDER_DISPLAY or PR_DISPLAY_NAME

    PR_ENTRYID properties

    PR_MDB_PROVIDER

    PR_RESOURCE_FLAGS

  3. Build a restriction to filter out the row that represents the message store to be opened. To look for the default message store, see Opening the Default Message Store. To look for a message store by name, apply any of the following property restrictions:
    • Match PR_PROVIDER_DISPLAY with the general name for this type of message store. For example, PR_PROVIDER_DISPLAY might be set to "Personal Folders."
    • Match PR_MDB_PROVIDER with the specific name for this type of message store. For example, PR_MDB_PROVIDER might be set to "Microsoft Exchange Personal Folders."
    • Match PR_DISPLAY_NAME with the name for this particular message store. For example, PR_DISPLAY_NAME might be set to "My Messages for Fiscal Year 1995."
  4. Call HrQueryAllRows to retrieve the appropriate row from the message store table. The entry identifier for the row will be included in the property value array for the aRow member of the row set pointed to by the pprows parameter.
  5. Call FreePRows to free the row set pointed to by pprows.
  6. Release the message store table by calling its IUnknown::Release method.

If you have created a custom entry identifier for the message store to be opened, call the WrapStoreEntryID function to convert it to a standard entry identifier.

Once you have a message store's entry identifier, call one of the following methods to open it:

IMAPISession::OpenMsgStore

IMAPISession::OpenEntry

Call OpenMsgStore if you need to specify a variety of special options for the message store. OpenMsgStore allows you to suppress the display of dialog boxes, identify the message store as temporary or as a nonmessaging store, set access levels, and to defer errors. OpenEntry allows you only to set access levels and defer errors.

Setting the MDB_NO_MAIL flag indicates to MAPI that the message store will not be used for sending or receiving messages. MAPI does not inform the MAPI spooler about the existence of this message store. The MDB_TEMPORARY flag designates a message store as temporary, implying that it cannot be used to store permanent information. Temporary message stores do not appear in the message store table.


Opening the Default Message Store

In any particular session, one message store acts as the default message store. A default message store has the following characteristics:

  • The PR_DEFAULT_STORE property is set to TRUE.
  • The STATUS_DEFAULT_STORE flag is set in the PR_RESOURCE_FLAGS property.
  • MAPI automatically creates the IPM subtree and the root folders for search-results, common views and personal views when the message store is opened. For more information about these folders, see IPM Subtree and Special Folders.

To retrieve the entry identifier for the default message store, you must call IMAPISession::GetMsgStoresTable to open the message store table and apply an appropriate restriction in a call to HrQueryAllRows. HrQueryAllRows will return a row set with the one row that represents the default message store. The restriction that you pass to HrQueryAllRows can take on one of the following forms:

  1. An AND restriction that uses an SAndRestriction structure to combine:
    • An exists restriction that uses an SExistRestriction structure to test for the existence of the PR_DEFAULT_STORE property.
    • A property restriction that uses an SPropertyRestriction structure to check for the TRUE value in the PR_DEFAULT_STORE property.
  2. A bitmask restriction that uses an SBitMaskRestriction structure for applying STATUS_DEFAULT_STORE as a mask against the PR_RESOURCE_FLAGS property.


Validating and Initializing a Message Store

When you open a message store through the IMAPISession::OpenMsgStore method without setting the MDB_NO_MAIL flag, MAPI creates several folders and assigns them default names and roles. MAPI is responsible for creating these folders to avoid the incompatibilities that would inevitably occur if either clients or message store providers were responsible for the creation.

Sometimes it is necessary to verify that the appropriate folders have been created and that they are valid. The HrValidateIPMSubtree function is available for this purpose. If you are validating the default message store, pass the MAPI_FULL_IPM_TREE flag. A more extensive group of folders is created for the default message store. When HrValidateIPMSubtree receives the MAPI_FULL_IPM_TREE flag, it checks for the following folders:

  • Root folder for the IPM subtree
  • Deleted Items folder in the IPM root folder
  • Inbox folder in the IPM root folder
  • Outbox folder in the IPM root folder
  • Sent Items folder in the IPM root folder
  • Folder views in the message store's root folder
  • Common views in the message store's root folder
  • Search folder in the message store's root folder

If the message store is not the default, you can either set or not set the MAPI_FULL_IPM_TREE flag. When this flag is not set, HrValidateIPMSubtree checks for only the root folder for the subtree, the Deleted Items folder, and the root folder for message store search results.

To initialize a message store, store the following properties in memory so that they are readily available:

PR_VALID_FOLDER_MASK

PR_STORE_SUPPORT_MASK

These properties are bitmasks that describe features of the message store. PR_VALID_FOLDER_MASK has one bit set for every special folder that exists in the message store and has an assigned entry identifier that is valid. See Opening a Folder for more information about accessing these folders and their entry identifiers.

PR_STORE_SUPPORT_MASK has one bit set for every feature supported in the message store. For example, if a message store supports notification and formatted text, its PR_STORE_SUPPORT_MASK will have the STORE_NOTIFY_OK and STORE_RTF_OK bits set.

Other properties that should be stored locally include the entry identifiers for the folders that the PR_VALID_FOLDER_MASK property describes as valid. Each of these special folders, except for the Inbox folder, has an entry identifier property associated with it. For example, the entry identifier for the Outbox folder is its PR_IPM_OUTBOX_ENTRYID property. Because these folders are the folders that will be opened frequently, it is a good idea to have their entry identifiers readily available.


Searching a Message Store

Client applications can search through one or more folders looking for messages that match search criteria. The most straightforward search technique involves applying a restriction to define criteria and placing the results into a search-results folder, created explicitly for this search or for a prior search. Not all message stores support this technique. To determine whether or not the message store you are using supports using search-results folders, call its IMAPIProp::GetProps method to retrieve the PR_STORE_SUPPORT_MASK property. If the STORE_SEARCH_OK flag is set, searching is supported. If it is not set, you'll need an alternate approach such as manually inspecting the target folders.

To search one or more folders in a message store
  1. If you have a search-results folder from a previous search, skip to step 2. Otherwise, to create a search-results folder:
    1. Retrieve the entry identifier for the search-results root folder by calling the message store's IMAPIProp::GetProps method and requesting PR_FINDER_ENTRYID.
    2. Call IMsgStore::OpenEntry to open the folder represented by PR_FINDER_ENTRYID.
    3. Call the folder's IMAPIFolder::CreateFolder method to create a search-results folder with the FOLDER_SEARCH flag set.
  2. Build a restriction to hold your search criteria.
  3. Create an array of entry identifiers that represent the folders to search. This step is unnecessary if the search-results folder has been used before and you want to search the same folders.
  4. Call the search-results folder's IMAPIContainer::SetSearchCriteria method, pointing lpContainerList to the entry identifier array and lpRestriction to the restriction.
  5. If you have registered for search complete notifications with the message store, wait for the notification to arrive.
  6. View the results of the search by calling the search-results folder's IMAPIContainer::GetContentsTable method to access its contents table.
  7. Call the contents table's IMAPITable::QueryRows method to retrieve the messages that satisfy the search criteria.


Selecting a Receive Folder

A receive folder is where incoming messages of a particular class are placed. For IPM and related report messages, MAPI assigns the Inbox as the default receive folder. For IPC and related report messages, MAPI assigns the root folder of the message store as the default receive folder. You can change these assignments or make additional assignments for other message classes. Making explicit receive folder assignments for your client's supported message classes is optional.

When an incoming message class does not have an assigned receive folder, the message store provider automatically uses the receive folder for the class that matches the longest possible prefix of the incoming class. For example, if your client receives a message of class IPM.Note.MyDocument and the only receive folder that has been established is the Inbox for IPM messages, this message will be placed in the Inbox because IPM.Note.MyDocument derives from the base class IPM.

When you are assigning a receive folder for IPC messages, never use a folder from the IPM subtree. These folders should be reserved for IPM messages only. Use instead a folder that is contained within the message store's root folder.

To create a receive folder for an IPM message class
  1. Call the message store's IMAPIProp::GetProps method to retrieve the PR_IPM_SUBTREE_ENTRYID property.
  2. Call IMsgStore::OpenEntry with PR_IPM_SUBTREE_ENTRYID as the entry identifier to open the root folder of the IPM subtree in the message store.
  3. Call IMAPIFolder::CreateFolder to create the receive folder.
  4. Call IMsgStore::SetReceiveFolder to map the new folder to your IPM message class.
To create a receive folder for an IPC message class
  1. Call IMsgStore::OpenEntry with a null entry identifier to open the root folder of the message store.
  2. Call IMAPIFolder::CreateFolder to create the receive folder.
  3. Call IMsgStore::SetReceiveFolder to map the new folder to your IPC message class.

Assign the receive folder that you use for messages for related report messages. For example, if your client receives IPM.Note messages, set up one receive folder for future IPM.Note messages and the same receive folder for future Report.IPM.Note messages.

Note Use the IMsgStore::SetReceiveFolder method for more than establishing a receive folder association with messages of a particular class. The character string passed to SetReceiveFolder does not necessarily need to represent a message class. For example, you can map a folder to a character string, making it easier to find the folder when necessary. The most obvious alternative for associating folders to strings is to use message store named properties, an approach that is not recommended because MAPI does not define a range of message store properties for use by clients, and message store providers do not always support named properties.


Opening a Folder

Before any folder can be opened, its entry identifier must be available. For most folders, this means retrieving their PR_ENTRYID properties. For special folders, such as some of the IPM subtree folders and other root folders, MAPI defines special entry identifier properties that are accessible by calling the message store's IMAPIProp::GetProps method. These entry identifiers are always long-term and are named as follows:

Folder | Entry identifier property
Outbox folder | PR_IPM_OUTBOX_ENTRYID (IPM message class only)
Deleted Items folder | PR_IPM_WASTEBASKET_ENTRYID
Sent Items folder | PR_IPM_SENTMAIL_ENTRYID
IPM root folder | PR_IPM_SUBTREE_ENTRYID
Search-results root folder | PR_FINDER_ENTRYID
Common views root folder | PR_COMMON_VIEWS_ENTRYID
Personal views root folder | PR_VIEWS_ENTRYID

Before you try to retrieve one of these special entry identifiers, retrieve the PR_VALID_FOLDER_MASK property of the message store. PR_VALID_FOLDER_MASK is a bitmask that identifies which of the special entry identifiers exist. There is one bit for each of the special folders. If the bit is set, it indicates that the corresponding folder is supported and has a valid entry identifier. For example, if the Deleted Items folder exists and has a valid entry identifier, the FOLDER_IPM_WASTEBASKET_VALID bit will be set in PR_VALID_FOLDER_MASK.

To open the folder where all incoming messages of a particular class are placed
  1. Call IMsgStore::GetReceiveFolder to retrieve its entry identifier, setting the lpszMessageClass parameter to point to a character string identifying the message class.

    For example, if you want to open the Inbox for your IPM subtree, point lpszMessageClass to IPM. If you want to open the receive folder for IPC messages, set it to point to IPC. If there is no registered receive folder for the message class, GetReceiveFolder chooses the receive folder whose associated message class matches the longest possible prefix of the message class passed in. See Receive Folders for more information.

    Note that the PR_IPM_OUTBOX_ENTRYID property is used to open the Outbox folder only for IPM messages. If you are opening the Outbox for IPC messages, use instead the entry identifier for its receive folder. Both incoming and outgoing IPC messages are placed in the receive folder.

  2. Call one of four OpenEntry methods to open the folder and return an interface pointer that you can use to access it. You can call any one of the following methods to open a folder:

    IMAPISession::OpenEntry

    IMSLogon::OpenEntry

    IMsgStore::OpenEntry

    IMAPIContainer::OpenEntry

    The specific method that you choose depends on the folder to be opened and the objects that are available at the time. Because the IMAPISession method can open any folder for any message store in the current profile, call this OpenEntry when you do not know anything about the folder to be opened.

    If you know which message store owns the folder and you have a pointer to the message store, call IMsgStore::OpenEntry. For example, use the IMsgStore method to open a receive folder. If you have a pointer to the message store provider's logon object, call IMSLogon::OpenEntry. Because these calls go directly to the message store provider rather than through MAPI, processing is faster.

    If the folder you are opening is a subfolder of a folder that you already have open, call the open folder's IMAPIContainer::OpenEntry method. The IMAPIContainer method only opens subfolders of a currently opened folder and is the only method guaranteed to work with short-term entry identifiers.

  3. If you want to be able to make changes to the folder to be opened, specify an access level by setting either the MAPI_BEST_ACCESS or MAPI_MODIFY flag in the OpenEntry call.

    These flags are suggestions to the message store provider to grant the highest level of access, for MAPI_BEST_ACCESS, or read/write access, for MAPI_MODIFY, when opening the folder. Because these flags are only suggestions, the folder may or may not be opened with the access level you expect. By retrieving the PR_ACCESS property, you can determine the range of operations that can be performed on the open folder. However, because many message store providers calculate the value for this property on demand rather than supporting it as a folder property or as a column in their hierarchy table, retrieving it can be time-consuming. An alternate strategy is to attempt whatever operation you need to perform and return an error if necessary.


Displaying a Folder Contents Table

The contents table of a folder contains summary information about all of its messages. Summary information about new incoming messages appears in the contents table of the receive folder for the message class. To make this information available to users, retrieve the table and display the columns and rows as appropriate.

To display a folder contents table
  1. Call IMsgStore::OpenEntry, passing the entry identifier of the folder containing the table.
  2. Call the folder's IMAPIContainer::GetContentsTable method to open its contents table.
  3. Limit your view of the contents table if desired by calling the table's IMAPITable::SetColumns method to specify particular columns.
  4. Limit your view of the contents table if desired by calling the table's IMAPITable::Restrict method to filter particular rows. If, for example, you want to show only messages with a specific message class that have yet to be read:
    1. Create a property restriction in an SPropertyRestriction structure that matches the PR_MESSAGE_CLASS property with the desired message class.
    2. Create a bitmask restriction in an SBitmaskRestriction structure that uses PR_MESSAGE_FLAGS as the property tag and the MSGFLAG_UNREAD value as the mask.
    3. Create a restriction in an SAndRestriction structure that joins the property and bitmask restrictions.
  5. Sort the contents table if desired by calling the table's IMAPITable::SortTable method.
  6. Call IMAPITable::QueryRows to retrieve all of the rows from the contents table for processing.

Transport providers set the PR_MESSAGE_FLAGS property of incoming messages to MSGFLAG_FROMME if they were sent by the currently logged on user. If this flag is set and you are displaying the contents table of the Sent Items folder, show names of recipients rather than names of senders. Messages that have been saved during the composition process and not yet sent should also be displayed with recipient names rather than sender names.


Traversing the Inbox Folder

To cycle through all of the messages in the Inbox
  1. Call IMsgStore::GetReceiveFolder to retrieve the entry identifier of the Inbox.
  2. Call IMAPIFolder::OpenEntry to open the Inbox.
  3. Call the Inbox's IMAPIContainer::GetContentsTable method to retrieve the contents table.
  4. Call the contents table's IMAPITable::SetColumns method to limit the column set to PR_ENTRYID and any other columns you require.
  5. Call IMAPITable::QueryRows to retrieve a group of rows.
  6. Until there are no longer any rows in the contents table:
    1. Call IMsgStore::OpenEntry to open the message represented by the entry identifier from each row.
    2. Assign the lppUnk parameter to a local IMessage interface pointer.
    3. Work with the properties of the message.
    4. Release the pointer pointed to by the lppUnk parameter.
    5. Call IMAPITable::QueryRows to retrieve the next group of rows.
  7. Release the contents table.


Copying or Moving a Message or a Folder

A client can use one of four methods to copy or move a message or a folder:

IMAPIFolder::CopyFolder

IMAPIFolder::CopyMessages

IMAPIProp::CopyTo

IMAPIProp::CopyProps

By setting the appropriate flags and parameters, CopyTo and CopyProps can by made to work just like CopyFolder or CopyMessages. Consider the following issues when deciding which method to call:

  • Are you copying or moving a folder or a message?
  • How much do you know about the folder or message to be moved or copied?
  • How many of the folder or message's properties will be moved or copied?

You can use the IMAPIProp methods to copy or move either a folder or a message. IMAPIFolder::CopyMessages works with messages only; IMAPIFolder::CopyFolder works with folders only.

Whereas using the IMAPIFolder methods does not require any knowledge of the properties supported by the folder or message to be copied or moved, you must have some knowledge to use the IMAPIProp methods. With IMAPIProp::CopyProps, you must be able to explicitly specify which of the folder or message properties that you want to copy or move. With IMAPIProp::CopyTo, unless you want to copy or move all of the properties, you must explicitly specify which ones should be excluded. For more information about these methods, see Copying Properties.

The number of properties to be copied or moved can affect your decision as to which method to use. If you are copying or moving multiple messages, call IMAPIFolder::CopyMessages. An alternate choice is to call IMAPIProp::CopyProps to copy only the folder's PR_CONTAINER_CONTENTS property. The following procedure shows how to use CopyMessages.

To copy or move one or more messages
  1. Locate valid entry identifiers for the source and destination folders.
  2. Open these folders in read/write mode by calling either IMAPISession::OpenEntry or IMsgStore::OpenEntry and setting the MAPI_MODIFY flag.
  3. Check that the interface pointer returned from OpenEntry is an IMAPIFolder interface pointer. If not, cast it to the LPMAPIFOLDER type.
  4. Create an array of entry identifiers representing the one or more messages to be copied or moved.
  5. Call IMAPIFolder::CopyMessages with the following flags set:
    • MESSAGE_MOVE, if you want to perform a move operation.
    • MESSAGE_DIALOG and pass a window handle in the ulUIParam parameter, if you want the folder to show a progress indicator.
  6. Release the IMAPIFolder pointers for the source and destination folders.

If you want to copy the complete contents of a folder to another folder, call the source folder's IMAPIFolder::CopyFolder or IMAPIProp::CopyTo method.

To copy a few of a folder's properties, call its IMAPIProp::CopyProps method. To copy most of a folder's properties, call IMAPIProp::CopyTo.

For example, if you want to copy a folder's PR_DISPLAY_NAME and PR_COMMENT properties, you have the following options:

  • Call IMAPIFolder::CopyFolder to copy all of the folder properties and then delete the unwanted ones from the new folder.
  • Call CopyTo and exclude all of the folder's properties except for PR_DISPLAY_NAME and PR_COMMENT.
  • Call CopyProps, passing PR_DISPLAY_NAME and PR_COMMENT in the include array.

In this case, CopyProps is the best choice because it is meant to be used to copy a small set of properties and is the easiest call to implement.

To copy or move only folder properties, without including messages, call the folder's IMAPIProp::CopyTo method and exclude the following properties:

PR_CONTAINER_CONTENTS

PR_FOLDER_ASSOCIATED_CONTENTS

The copy methods can return S_OK, indicating total success, MAPI_W_PARTIAL_COMPLETION, indicating partial success, or an error. If MAPI_W_PARTIAL_COMPLETION is returned, use the HR_FAILED macro to access a more specific error. See Using Macros for Error Handling.

If you copy messages from one message store to another and Unicode is not supported by both, be aware that information can be lost due to code page conversion. Usually you cannot know if the message stores support one or both formats, making it impossible to determine whether to copy text properties as ASCII strings or as Unicode strings. If you support Unicode, try to perform a Unicode copy; if it fails with the error value MAPI_E_BAD_CHARWIDTH, resort to ASCII.


Opening a Message

To open a message
  1. Retrieve the message's entry identifier from one of the following sources:
    • The row that represents the message in the contents table of its parent folder. For more information about working with a folder contents table, see Contents Tables.
    • The lpEntryID member of the NEWMAIL_NOTIFICATION structure that is sent with a new mail notification. For more information about receiving and handling notifications, see Handling Notifications.
    • A call to the message's IMAPIProp::GetProps method requesting the PR_ENTRYID property.
  2. Call one of the following OpenEntry methods to open the message, setting lpEntryID to the message's entry identifier:

    IMAPIFolder::OpenEntry

    IMsgStore::OpenEntry

    IMAPISession::OpenEntry

    The fastest method is usable only for incoming messages and involves calling the receive folder's IMAPIFolder::OpenEntry method. The next fastest method, calling the message store's IMsgStore::OpenEntry method, is usable for all messages as is the slowest method, calling IMAPISession::OpenEntry.

Note Folders and their contents tables can be closed at any time without adversely affecting any of the messages that were opened from within them.

To open a message that has been saved on disk
  1. Call StgOpenStorage to retrieve an IStorage interface pointer, passing the name of the message file for the pwcsName parameter.
LPSTORAGE pStorage = NULL;
HRESULT hr = StgOpenStorage (L"MESSAGE.MSG", NULL,
                             STGM_TRANSACTED |
                             STGM_READWRITE |
                             STGM_SHARE_EXCLUSIVE,
                             NULL, 0, &pStorage);
  2. Call OpenIMsgOnIStg to retrieve an IMessage interface pointer to access the message.
LPMESSAGE pMessage = NULL;
LPMALLOC pMalloc = MAPIGetDefaultMalloc();
hr = OpenIMsgOnIStg (NULL, MAPIAllocateBuffer, MAPIAllocateMore,
                     MAPIFreeBuffer, pMalloc, NULL, pStorage,
                     NULL, 0, 0, &pMessage);


Finding the Icon for a Message

To find the icon associated with a message
  1. Call the message's IMAPIProp::GetProps method to retrieve its PR_MESSAGE_CLASS property.
  2. Call MAPIOpenFormMgr to retrieve an IMAPIFormMgr interface pointer. Pass your IMAPISession pointer in the pSession parameter.
  3. Call IMAPIFormMgr::ResolveMessageClass to retrieve an IMAPIFormInfo interface pointer.
  4. Use the IMAPIFormInfo pointer to call IMAPIProp::GetProps and retrieve the PR_ICON and/or PR_MINI_ICON properties.


Opening a View Descriptor

Many folders can be opened with a normal view, a default view, or any number of personalized views. A view describes how to display the contents of a folder. The normal view is used when there is no alternative view and when you are opening the folder for the first time. When an alternative view does exist, you must use it to open the folder.

A view is described in a message known as a view descriptor. View descriptors are typically created as associated messages and can appear in either the common or personal view folders or in any IPM folder.

To open a view descriptor
  1. Call IMAPIContainer::GetContentsTable to retrieve the associated contents table for the folder.
  2. Create a restriction that locates only messages with the message class reserved for view descriptors and call IMAPITable::Restrict to limit the table and IMAPITable::QueryRows to retrieve the appropriate rows.

    – Or –

    Call the folder's IMAPIProp::GetProps method to retrieve its PR_DEFAULT_VIEW_ENTRYID property. PR_DEFAULT_VIEW_ENTRYID contains the entry identifier for the message containing the default view descriptor for a folder. This call will succeed if the folder supports the use of the MAPI_ASSOCIATED flag on calls to IMAPIFolder::CreateMessage and IMAPIContainer::GetContentsTable.

  3. Call IMsgStore::OpenEntry with the entry identifier of the view descriptor to open it.


Deleting a Message

A client can delete a message when it is open and the user is reading it, or when it is closed and the user is viewing the contents table. To protect a user from inadvertently removing a message, MAPI defines message deletion as a two step process:

  1. Mark a message for deletion by moving it to the folder that has been designated as the Deleted Items folder — the folder whose entry identifier is stored in the PR_IPM_WASTEBASKET_ENTRYID property.
  2. Remove the message by calling the IMAPIFolder::DeleteMessages method.

When a user chooses to delete a message in a folder other than the Deleted Items folder, mark it for deletion. Only when a user selects messages from within the Deleted Items folder should the messages be physically removed from the workstation. You can prompt the user to verify that the user really intended to perform the deletion.

To delete a message
  1. Confirm with the user that the impending deletion is intentional.
  2. Determine the parent of the folder to be deleted. If it is the Deleted Items folder or a subfolder within the Deleted Items folder, call DeleteMessages to remove the message.
  3. If the folder is not contained within the Deleted Items folder, call CopyMessages with the MESSAGE_MOVE flag set to relocate the message to the Deleted Items folder.


Saving a Message in the Inbox

To store a message in the Inbox without any recipients
  1. Call IMsgStore::GetReceiveFolder to retrieve the entry identifier of the Inbox.
  2. Call IMsgStore::OpenEntry to open the Inbox and retrieve a pointer to it.
  3. Call the Inbox's IMAPIFolder::CreateMessage method to create the message.
  4. Call the message's IMAPIProp::SetProps method to add the PR_BODY or PR_RTF_COMPRESSED and PR_SUBJECTproperties.
  5. Create each attachment, set its properties, and save it. For detailed information about adding attachments to messages, see Creating a Message Attachment.
  6. Call IMessage::SaveChanges to save the message. At this point it will appear in the contents table of the Inbox.

If you want to save a message intermittantly before having it appear in the contents table of the Inbox, create it instead in a hidden folder such as the root folder of the IPM subtree and then move it to the Inbox.


Finding Sent or Saved Messages

To locate all the outgoing messages that you have saved or sent
  1. Call IMsgStore::CompareEntryIDs to compare the folder that contains your sent messages with the folder that contains your incoming messages.
  2. Set the lpEntryID1 parameter to point to PR_IPM_SENTMAIL_ENTRYID and the lpEntryID2 parameter to point to PR_PARENT_ENTRYID.

Be aware that if you either delete messages after they are sent or have moved any of the sent messages to another folder, this strategy will not work.

If in examining an incoming message you notice that the properties that are typically set by a transport provider are missing, you can assume that the message was never handled by a transport provider. These properties include:

PR_RECEIVED_BY properties

PR_MESSAGE_DOWNLOAD_TIME

PR_TRANSPORT_MESSAGE_HEADERS

PR_MESSAGE_TO_ME

PR_MESSAGE_CC_ME

PR_MESSAGE_RECIP_ME


Tracking Conversations

Conversation tracking is collecting responses to a message. Clients should set two properties that aid in tracking conversations:

PR_CONVERSATION_TOPIC

PR_CONVERSATION_INDEX

PR_CONVERSATION_TOPIC is the normalized subject of the message, the subject without the prefix strings. Set this property to the value of the message's PR_NORMALIZED_SUBJECT property.

PR_CONVERSATION_INDEX indicates the position of the message within a particular conversation. It is a client's reponsibility to set PR_CONVERSATION_INDEX for each outgoing message, whether it is a new message, a forwarded message, or a reply. Clients can set this property manually or call ScCreateConversationIndex, a utility function provided by MAPI.

ScCreateConversationIndex generates the value of a conversation index for any outgoing message. ScCreateConversationIndex implements the index as a header block that is 22 bytes in length, followed by zero or more child blocks each 5 bytes in length.

The header block is composed of 22 bytes, divided into three parts:

  • One reserved byte. Its value is 1.
  • Five bytes for the current system time converted to the FILETIME structure format.
  • Sixteen bytes holding a GUID, or globally unique identifier.
  • Each child block is composed of 5 bytes, divided as follows:
  • One bit containing a code representing the difference between the current time and the time stored in the header block. This bit will be 0 if the difference is less than .02 second and greater than two years and 1 if the difference is less than one second and greater than 56 years.
  • Thirty one bits containing the difference between the current time and the time in the header block expressed in FILETIME units.This part of the child block is produced using one of two strategies, depending on the value of the first bit. If this bit is zero, ScCreateConversationIndex discards the high 15 bits and the low 18 bits. If this bit is one, the function discards the high 10 bits and the low 23 bits.
  • Four bits containing a random number generated by calling the Win32 function GetTickCount.
  • Four bits containing a sequence count that is taken from part of the random number.

If you choose to set the conversation indexes of messages manually, consider the following suggestions:

  1. Keep differences in the respondents' time zones transparent; use UTC times rather than local time.
  2. Indent each conversation group by the same amount.
  3. Sort responses to the same message date.
  4. Separate threads started at different times that happen to share the same topic.
  5. To implement a categorized sort so that messages are grouped by topic, sort by PR_CONVERSATION_TOPIC first and then by PR_CONVERSATION_INDEX. To present the results of the sort, set the PR_DEPTH property to 0 for messages with a conversation index that is 22 bytes in length. Then, for every 5-byte increment in the length, increment the value of the PR_DEPTH property by one.

The PR_ORIGINAL group of properties can also be used for conversation tracking. Set these properties to link reply or forwarded messages to the original message. All of the PR_ORIGINAL properties are optional. If you do not explicitly set, for example, PR_ORIGINAL_AUTHOR_ENTRYID, the message store provider can use the default value, or the value of the PR_SENDER_ENTRYID property. Likewise, if you do not set PR_ORIGINAL_AUTHOR_NAME or PR_ORIGINAL_SUBMIT_TIME, these properties can default to the values of the PR_SENDER_NAME and PR_CLIENT_SUBMIT_TIME properties, respectively.


Handling the Address Book

Handling the MAPI address book can include extracting entries to be used as message recipients, modifying recipient properties, adding messaging users or distribution lists, creating one-offs, and displaying one or more of the common address dialog boxes to allow users to browse address information and make changes.


Opening the Address Book

Call IMAPISession::OpenAddressBook to open the integrated address book and retrieve a pointer to the MAPI IAddrBook interface. The methods of the IAddrBook interface can be used to access entries in all of the containers of each of the address book providers in the profile.

OpenAddressBook might return a warning, MAPI_W_ERRORS_RETURNED, to indicate that there were problems with one or more of the address book providers. Interactive clients should call IMAPISession::GetLastError to retrieve additional error information and display the returned information the first time they call OpenAddressBook and it returns a warning.

Noninteractive clients should ignore the warning and proceed as if the method succeeded. The returned IAddrBook interface is valid regardless of whether all of the address book providers in the profile are running, some of them, or none of them. Therefore, both interactive and noninteractive clients must always remember to release the IAddrBook pointer when the session ends.


Displaying the Common Address Dialog Box

The MAPI common address dialog box can be used for a variety of addressing tasks such as constructing a recipient list. To display this dialog box, call IAddrBook::Address. Depending on which of the many parameters you set and how you set them, you can limit your display to entries of a particular type from a particular container.

To limit the address dialog box to displaying personal address book (PAB) entries only
  1. Call IAddrBook::GetPAB to retrieve the entry identifier of the PAB.
  2. Create a property restriction that uses RELOP_EQ for the relop member of the SPropertyRestriction structure and either PR_ENTRYID or PR_AB_PROVIDER_ID as the ulPropTag member.

    If you use PR_ENTRYID, pass the entry identifier retrieved from GetPAB. If you use PR_AB_PROVIDER_ID, pass the value included in the MSPAB.H header file. PR_AB_PROVIDER_ID is the unique identifier for the PAB designed by MAPI.

  3. Call IAddrBook::Address with the lpHierRestriction parameter pointing to the property restriction.


Opening an Address Book Container

After opening the MAPI integrated address book, open one or more address book containers to access the recipients within them.

To open the top-level container of the address book, call IAddrBook::OpenEntry with a NULL entry identifier.

Address book containers can be implemented with read-only or read/write access. Read-only containers are used only for browsing. Read/write containers can be modified, allowing clients to create new entries and delete and modify existing entries. All personal address book (PAB) containers are implemented as read/write containers.

To open any lower level container, call OpenEntry and specify the entry identifier of the container to be opened.

To open the container designated as the PAB
  1. Call IAddrBook::GetPAB to retrieve the PAB's entry identifier.
  2. Pass this entry identifier to IAddrBook::OpenEntry.
To open a container that is not the PAB
  1. Call IAddrBook::OpenEntry with a NULL entry identifier to open the address book's root container.
  2. Call the root container's IMAPIContainer::GetHierarchyTable method to retrieve its hierarchy table — a list of all of the top-level containers in the address book.
  3. If the container to be opened is of a specific type:
    • Create an SPropertyRestriction structure with PR_DISPLAY_TYPE for the property tag, the container's type for the property value, and RELOP_EQ for the relation. PR_DISPLAY_TYPE can be set to many values, among them:
· DT_GLOBAL to limit the hierarchy table to containers that belong in the global address list.
· DT_LOCAL to limit the table to containers belonging to a local address book.
· DT_MODIFIABLE to limit the table to containers that can be modified.

  • Create an SPropTagArray structure that includes PR_ENTRYID, PR_DISPLAY_TYPE, and any other columns of interest.
  • Call HrQueryAllRows, passing your property restriction and property tag array. HrQueryAllRows will return zero or more rows, one row for every container that belongs to the specified type. Be prepared to handle the return of any number of rows.
  • Call IAddrBook::OpenEntry with the entry identifier from the PR_ENTRYID column of the row that represents the container of interest.
  4. If the container to be opened belongs to a specific address book provider:
    • Create an SPropertyRestriction structure with PR_AB_PROVIDERS for the property tag, a provider-specific value for the property value, and RELOP_EQ for the relation. Typically the provider-specific value is a globally unique identifier or GUID. You will find this value published in one of the address book provider's header files.
    • Create an SPropTagArray structure that includes PR_ENTRYID, PR_AB_PROVIDER, and any other columns of interest.
    • Call HrQueryAllRows, passing your property restriction and property tag array. HrQueryAllRows will return zero rows if the specified address book provider is not in the profile. It can return one or more rows for the provider's top-level containers, depending on how the provider is organized.
    • Call IAddrBook::OpenEntry with the entry identifier from the PR_ENTRYID column of the row that represents the container of interest. If the container that you are interested in is not a top-level container, find the top-level container and traverse the hierarchy.


Setting Address Book Options

You can set three properties that describe options for using the address book:

PR_AB_SEARCH_PATH

PR_AB_DEFAULT_DIR

PR_AB_DEFAULT_PAB

The PR_AB_SEARCH_PATH property is used by IAddrBook::ResolveName to determine the containers to be involved in name resolution and the order that they should be involved. For each container in PR_AB_SEARCH_PATH, IAddrBook::ResolveName calls its IABContainer::ResolveNames method. Containers at the beginning of PR_AB_SEARCH_PATH are searched before containers at the end of PR_AB_SEARCH_PATH.

The search order in PR_AB_SEARCH_PATH is specified using an SRowSet structure, the same structure that is used to represent rows in a table. You can view the current search path by calling the IAddrBook::GetSearchPath method and change it by calling the IAddrBook::SetSearchPath method.

The PR_AB_DEFAULT_DIR property is the entry identifier of the address book container to be displayed initially when the address book is displayed. The default directory setting remains in effect until you change it by calling the IAddrBook::SetDefaultDir method. You can view the default directory by calling the IAddrBook::GetDefaultDir method.

The PR_AB_DEFAULT_PAB property is the entry identifier of the modifiable address book container that is to be used as the session's personal address book. Like PR_AB_DEFAULT_DIR, the value of PR_AB_DEFAULT_PAB remains in effect until it is changed. Logging off and logging back on do not affect their settings. Access the PR_AB_DEFAULT_PAB property by calling IAddrBook::GetPAB and change it by calling IAddrBook::SetPAB.

These three properties are special because you cannot work with them using the standard IMAPIProp methods. Instead, you must use IAddrBook methods. Because none of these properties can be changed with IMAPIProp::SetProps, there is no need to call IMAPIProp::SaveChanges to make changes permanent. Modifications made through the IAddrBook methods take effect immediately.


Creating a Recipient

Clients create recipients when they are addressing messages and when they are adding entries to modifiable address book containers. MAPI provides three methods for creating recipients:

IAddrBook::CreateOneOff

IAddrBook::NewEntry

IABContainer::CreateEntry

Call IAddrBook::CreateOneOff when you are creating recipients to be used to address messages. CreateOneOff creates a specially formatted one-off entry identifier to be associated with an address of a particular address type. For more information about one-offs and one-off entry identifiers, see One-Off Addresses and One-Off Entry Identifiers.

Call IAddrBook::NewEntry when you are creating recipients to be used either to address messages or to add to a container. NewEntry has three pairs of parameters that contain entry identifiers. These parameters are described as follows:

Parameter pair | Description
cbEidContainer and lpEidContainer | Entry identifier for the container into which the new entry should be placed.
cbEidNewEntryTpl and lpEidNewEntryTpl | Entry identifier for the template to be used to create the new entry.
lpcbEidNewEntry and lppEidNewEntry | Entry identifier for the new entry.

To create a recipient for an outgoing message, set cbEidContainer to zero and lpEidContainer to NULL. NewEntry creates a recipient with an entry identifier that conforms to the one-off format, the same type of recipient that is produced by a call to IAddrBook::CreateOneOff.

To create a recipient to be inserted into a particular container, set lpEidContainer to the container's entry identifier and cbEidContainer to the number of bytes in the container's entry identifier.

To use a template to create a recipient, set lpEidNewEntryTpl to the entry identifier of the template to be used and cbEidNewEntryTpl to the count of bytes in this entry identifier. Most modifiable address book containers support one or more templates for creating entries of a particular type. One-off templates are typically, but not always, dialog boxes. Entering information into the template produces a recipient with an address that is correctly formatted for the type.

Obtain the template entry identifier from either:

  • The PR_ENTRYID column in the container's one-off table, accessed by calling the container's IMAPIProp::OpenProperty method and specifying PR_CREATE_TEMPLATES as the property tag and IID_IMAPITable as the interface identifier.
  • An address book provider's PR_DEF_CREATE_MAILUSER and PR_DEF_CREATE_DL properties which hold the entry identifiers for the provider's messaging user object and distribution list templates.

Note Do not confuse a new entry template's entry identifier with a different type of entry identifier called a template identifier. A template identifier is used only by providers to maintain entries copied from other providers; it is never used by clients and it is not used to create new entries.

To allow the user to determine the type of entry to be created, pass zero for cbEidNewEntryTpl and NULL for lpEidNewEntryTpl. When this occurs, NewEntry displays a common dialog box built from MAPI's one-off table — a hierarchical list of all of the templates supported by each address book provider in the profile.

When an address type has been determined, either through the setting of the lpEidNewEntryTpl parameter or a selection by the user from the one-off table display, NewEntry displays the corresponding template using its display table. All new entry templates support the PR_DETAILS_TABLE property.

To have NewEntry return the entry identifier of the created entry, pass a valid address for the lpcbEidNewEntry and lppEidNewEntry parameters. MAPI places the new entry identifier at the address pointed to by lppEidNewEntry and the byte count of the new entry identifier at the address pointed to by lpcbEidNewEntry.

Call IABContainer::CreateEntry to create a recipient and save it into a particular address book container. You can use this method only with modifiable containers — containers that have the AB_MODIFIABLE flag set in their PR_CONTAINER_FLAGS property. Address book providers with nonmodifiable containers do not support this method. Specify the entry identifier of the template for creating an entry of the desired type in the lpEntryID parameter.

In the ulCreateFlags parameter, specify the type of duplicate entry checking required and whether or not new entries should replace existing ones. If CreateEntry fails to create a new object because of the duplicate entry checking imposed by the provider, do not expect to see an error or warning returned. Under these conditions, providers return a success code.

If you are working directly with a container and you know exactly the types of addresses that the container can create, you can call IABContainer::CreateEntry and pass the entry identifier for the appropriate template. The address book provider sets some initial default properties; you can call SetProps to set others. The user is never involved.


Creating a Distribution List

Clients can create a distribution list directly into a modifiable container such as the personal address book (PAB).

To create a distribution list in the PAB
  1. Create a sized property tag array with one property tag, PR_DEF_CREATE_DL, as follows:
SizedPropTagArray(1, tagaDefaultDL) =
{
    1,
    {
        PR_DEF_CREATE_DL
    }
};
  2. Call IAddrBook::GetPAB to retrieve the entry identifier of the PAB. If there is an error or GetPAB returns zero or NULL, do not continue.
LPENTRYID peidPAB = NULL;
ULONG cbeidPAB = 0;
lpIAddrBook->GetPAB(&cbeidPAB, &peidPAB);
  3. Call IAddrBook::OpenEntry to open the PAB. The ulObjType output parameter should be set to MAPI_ABCONT.
ULONG ulObjType = 0;
LPABCONT lpPABCont = NULL;
lpIAddrBook->OpenEntry(cbeidPAB, peidPAB,
                NULL,
                MAPI_MODIFY,
                &ulObjType,
                &lpPABCont);
  4. Call the PAB's IMAPIProp::GetProps method to retrieve the PR_DEF_CREATE_DL property, the template that it uses to create a distribution list.
lpPABCont->GetProps(0,
            tagaDefaultDL,
            &lpspvDefDLTpl);
  5. If GetProps fails:
    1. Call the PAB's IMAPIProp::OpenProperty method to open the PR_CREATE_TEMPLATES property with the IMAPITable interface.
    2. Create a property restriction to search for the row with the PR_ADDRTYPE column equal to "MAPIPDL."
    3. Call IMAPITable::FindRow to locate this row.
  6. Save the entry identifier returned by either GetProps or FindRow.
peidDefDLTpl = lpspvDefDLTpl->Value.bin.pb;
cbeidDefDLTpl = lpspvDefDLTpl->Value.bin.cb;
  7. Call the PAB's IABContainer::CreateEntry method to create a new entry using the template represented by the saved entry identifier. Do not assume that the object returned will be a distribution list rather than a messaging user when this call is remoted. Notice that the CREATE_CHECK_DUP flag is passed in the ulFlags parameter to prevent the entry from being added twice.
lpPABCont->CreateEntry(cbeidDefDLTpl,
                peidDefDLTPL,
                CREATE_CHECK_DUP_STRICT,
                &lpNewPABEntry);
  8. Call the new entry's IUnknown::QueryInterface method, passing IID_IDistList as the interface identifier, to determine if the entry is a distribution list and supports the IDistList interface. Because CreateEntry returns an IMAPIProp pointer rather than the more specific IMailUser or IDistList pointer, check that a distribution list object was created. If QueryInterface succeeds, you can be sure that you have created a distribution list rather than a messaging user.
  9. Call the distribution list's IMAPIProp::SetProps method to set its display name and other properties.
  10. Call the distribution list's IABContainer::CreateEntry method to add one or more messaging users.
  11. Call the distribution list's IMAPIProp::SaveChanges method when you're ready to save it. To retrieve the entry identifier of the saved distribution list, set the KEEP_OPEN_READWRITE flag and then call IMAPIProp::GetProps asking for the PR_ENTRYID property.
  12. Release the new distribution list and the PAB by calling their IUnknown::Release methods.
  13. Call MAPIFreeBuffer to release the memory for the entry identifier of the PAB and the sized property tag array.


Copying a Recipient

To copy one or more recipients from one container into another or the same container, first check that the target container is modifiable. Containers that are modifiable set the AB_MODIFIABLE flag in their PR_CONTAINER_FLAGS property.

To copy one or more entries into a modifiable container, call the destination container's IABContainer::CopyEntries method. Because copying address book entries can be time-consuming, CopyEntries accepts four input parameters: an array of entry identifiers for the entries to be copied, a window handle, a progress indicator, and a bitmask of flags.

The window handle and progress indicator are used by the address book provider to show the status of the operation to the user. If you want to display progress, pass a window handle for the parent window of the progress indicator in the ulUIParam parameter and do not set the AB_NO_DIALOG flag in the ulFlags parameter. If you have your own implementation of a progress indicator, pass a pointer to the implementation in the lpProgress parameter. If not, pass NULL. The address book provider will use the MAPI progress indicator implementation.

The bitmask of flags indicates whether or not you want to display a progress indicator and how duplicate entry checking should be handled. Set the AB_NO_DIALOG flag to suppress a progress indicator. Set the CREATE_CHECK_DUP_LOOSE flag to instruct the address book provider to loosely check for duplicates or the CREATE_CHECK_DUP_STRICT flag for stricter duplicate checking. Set the CREATE_REPLACE flag to have copied entries replace existing entries when the provider determines there are duplicates.

When copying into a personal address book (PAB) container, the provider copies some or all of the properties for each entry. Some PABs, such as the PAB supplied by MAPI, copy all of the properties. Other PABs eliminate properties. Because MAPI does not establish requirements for providers implementing container copy operations, you cannot make assumptions about the number and type of properties that are copied with an address book entry.


Deleting a Recipient

To remove one or more address book entries from a modifiable container
  1. Call the IABContainer::DeleteEntries method, passing an array of entry identifiers that represent the address book entries to be deleted.

    DeleteEntries can return a warning, MAPI_W_PARTIAL_COMPLETION, to indicate that it couldn't delete one or more of the entries. Test for this return value with the HR_FAILED macro and call the container's IMAPIProp::GetLastError method if more information about the problem is needed.

When you hold a pointer to a deleted entry's ADRENTRY structure in your cache, you will still be able to retrieve properties using its entry identifier. This is because the entry is only marked for deletion. MAPI maintains a level of access to these marked entries by design.


Preparing a Recipient

A client application prepares recipients by converting their short-term entry identifiers to long-term entry identifiers and possibly adding, changing, or reordering properties. You can prepare recipients that are part of a recipient list for a message or recipients that are unrelated to a message. Typically, clients call IAddrBook::PrepareRecips directly to translate short-term entry identifiers into long-term entry identifiers for recipients that are included in the common address dialog box. For recipients that are associated with an outgoing message, recipient preparation is handled by the name resolution process.

To prepare a list of recipients, call IAddrBook::PrepareRecips. PrepareRecips accepts an ADRLIST structure and a list of property tags. The ADRLIST structure contains the recipients to be prepared while the property tag list represents properties that each recipient should support. PrepareRecips attempts to place the properties that are included in the property tag list at the beginning of the ADRLIST structure. If any of the properties in the list are missing from the ADRLIST structure, MAPI calls the address book provider to supply them. If you only need to check for long-term entry identifiers, pass NULL for the lpSPropTagArray parameter.

For example, suppose you are working with five recipients. All five recipients appear in the ADRLIST structure with the following properties in the following order:

  1. PR_ENTRYID
  2. PR_DISPLAY_NAME
  3. PR_SEARCH_KEY
  4. PR_EMAIL_ADDRESS
  5. PR_ADDRTYPE

Three other properties are included in the ADRLIST structure for the first two recipients.

  1. PR_ACCOUNT
  2. PR_GIVEN_NAME
  3. PR_SURNAME

Because all of the recipients need to have as their first three properties PR_ADDRTYPE, PR_ENTRYID, and PR_HOME_TELEPHONE_NUMBER, create a property tag array with these properties and pass it and the ADRLIST structure to PrepareRecips. PrepareRecips calls each recipient's IMAPIProp::GetProps method to retrieve PR_HOME_TELEPHONE_NUMBER because it is not currently part of the ADRLIST structure. When PrepareRecips returns, the recipient list represents a merged list of recipients with the properties included in the ADRLIST structure appearing first for each recipient.

The recipient list for recipients 1 and 2 includes properties in the following order:

  1. PR_ADDRTYPE
  2. PR_ENTRYID
  3. PR_HOME_TELEPHONE_NUMBER
  4. PR_DISPLAY_NAME
  5. PR_SEARCH_KEY
  6. PR_EMAIL_ADDRESS
  7. PR_ADDRTYPE
  8. PR_ACCOUNT
  9. PR_GIVEN_NAME
  10. PR_SURNAME

The recipient list for recipients 3, 4, and 5 includes properties in the following order:

  1. PR_ADDRTYPE
  2. PR_ENTRYID
  3. PR_HOME_TELEPHONE_NUMBER
  4. PR_DISPLAY_NAME
  5. PR_SEARCH_KEY
  6. PR_EMAIL_ADDRESS
  7. PR_ADDRTYPE

As an alternative to calling IAddrBook::PrepareRecips to work with properties, call each recipient's IMAPIProp::GetProps method and, if necessary, its IMAPIProp::SetProps method. When only one recipient is involved, either technique is satisfactory. However, when multiple recipients are involved, calling PrepareRecips rather than the IMAPIProp methods saves time and, if you are operating remotely, many remote procedure calls. PrepareRecips processes all recipients in a single call whereas GetProps and SetProps make one call for each recipient.


Accessing the Members of a Distribution List

To get the members of a distribution list
  1. Create a sized property tag array with the properties of the members you would like to retrieve, such as PR_ENTRYID, PR_DISPLAY_NAME, and PR_DISPLAY_TYPE.
  2. Call IAddrBook::OpenEntry to open the distribution list.
  3. Call the distribution list's IABContainer::GetContentsTable method to access its contents table.
  4. Call HrQueryAllRows to retrieve all of the table's rows representing the members of the distribution list.


Retrieving Recipient Properties

To access one or more properties of an address book entry
  1. For each address book entry of interest, call IAddrBook::OpenEntry, passing the entry identifier of the target messaging user or distribution list.
  2. For each address book entry of interest, call the messaging user or distribution list's IMAPIProp::GetProps method with a list of the one or more properties to retrieve.

    – Or –

    Call IAddrBook::PrepareRecips, passing an ADRLIST structure that holds all of the properties for all of the desired address book entries. Because one call to PrepareRecips can return information for multiple address book entries, it is the preferable strategy when you are interested in more than one recipient.


Searching the Address Book

MAPI enables address book providers to implement two levels of search functionality:

  • A basic level that matches a specified name with the PR_DISPLAY_NAME property of address book entries. This level allows users, for example, to view distribution lists with names beginning with Northwest or locate individual messaging users whose last name is Brown.
  • An advanced level that matches on properties other than PR_DISPLAY_NAME. This level allows users, for example, to further narrow their searches and find messaging users named Brown with a particular address type.

Because address book providers can support searching for each of their containers at the basic level, at both levels, or choose not to support it at all, do not expect searching to be implemented as a standard feature. To determine if a particular container supports searches, attempt to establish search criteria in a call to its IMAPIContainer::SetSearchCriteria method. If SetSearchCriteria returns MAPI_E_NO_SUPPORT, the container does not support searches.

In a container that supports searches, retrieve established criteria by calling IMAPIContainer::GetSearchCriteria. You can also request that the user be prompted for search criteria before a container's contents table is displayed. To choose this option, set the AB_FIND_ON_OPEN flag of the container's PR_CONTAINER_FLAGS property. After the user enters the criteria, it is stored as a restriction and passed to the SetSearchCriteria method. Setting AB_FIND_ON_OPEN is particularly useful if you are using an online service or any address book provider that has a slow link to its data.

To perform a basic search in an address book container
  1. Call the container's IMAPIContainer::GetContentsTable method to open its contents table.
  2. Choose a search technique that meets your needs. The choices include:
    • IMAPITable::FindRow to locate a specific row in the table.
    • IMAPITable::SortTable to order rows in the table.
    • IMAPITable::Restrict to limit the table view.
    • Property restriction using the PR_ANR property for resolving ambiguous names. Call IMAPITable::Restrict to impose this restriction.
    • IABContainer::ResolveNames to resolve ambiguous names.
  3. Call IMAPITable::QueryRows to retrieve any rows that meet your applied search criteria. QueryRows can return zero or more matching rows.

The FindRow, SortTable, and Restrict methods are table methods that are available for any table that can be created, either by a client or a service provider. The PR_ANR property restriction and IABContainer::ResolveNames method are specific to address book providers and are used for resolving ambiguous names. Ambiguous names are entries in a recipient list that do not have a PR_ENTRYID property associated with them.

The PR_ANR restriction invokes an algorithm that separates a character string into words and matches those words with information in the address book using prefix-matching. The information used for the matching depends on the address book provider. All address book providers are required to support the PR_ANR restriction for their address book containers. For more information, see Implementing Name Resolution.

IABContainer::ResolveNames performs PR_ANR restriction processing on multiple names without requiring the container's contents table to be open. Calling ResolveNames once to resolve multiple names can be much faster than invoking a PR_ANR restriction multiple times. However, address book providers are not required to support ResolveNames.


Using an Advanced Search Dialog Box

Some address book containers support an advanced searching capability that allows clients to search on properties other than PR_DISPLAY_NAME. Address book containers that support advanced searches have a container object property called PR_SEARCH. This container object provides access to a display table that describes the search dialog box — a dialog box used to enter and edit the advanced search criteria.

To perform an advanced search on an address book container
  1. Call the container's IMAPIProp::OpenProperty method, specifying PR_SEARCH for the property tag and IID_IMAPIContainer for the interface identifier.
  2. Call the search object 's IMAPIProp::OpenProperty method, specifying PR_DETAILS_TABLE for the property tag and IID_IMAPITable for the interface identifier.
  3. Call the search object's IMAPIProp::SetProps method to establish values for the properties to be used in the advanced search.
  4. Call the search object's IMAPIProp::SaveChanges method to save the advanced search criteria.

This sequence of calls results in a restriction being available when a client calls the search object's GetSearchCriteria method.


Resolving a Name

When a message is addressed, a recipient list is built with properties relating to each recipient. By the time the message is sent, one of those properties must be the recipient's long-term entry identifier. To ensure that each recipient includes the PR_ENTRYID property, pass the ADRLIST structure describing your recipient list in the contents of the lpAdrList parameter in a call to IAddrBook::ResolveName.

ResolveName begins processing by ignoring the entries in the ADRLIST structure that have already been resolved, as indicated by the presence of an entry identifier in the corresponding ADRENTRY structure's SPropValue array. Next, ResolveName automatically assigns one-off entry identifiers to two types of recipients:

  • Recipients with an address formatted as an Internet address
  • Recipients with an address formatted as follows:
    displayname[address type:e-mail address]

For all remaining entries, ResolveName searches the address book for an exact match on the display name. ResolveName uses the PR_AB_SEARCH_PATH property to determine the set of containers to search and the search order. MAPI calls the IABContainer::ResolveNames method of every container to attempt to resolve all of the names. Because some containers do not support ResolveNames, if the container returns MAPI_E_NO_SUPPORT, MAPI applies a PR_ANR property restriction against its contents table. All address book containers are required to support name resolution with this restriction. Once all the names are resolved, no further container calls are made. If all the containers have been called, but ambiguous or unresolved names remain, MAPI displays a dialog box if possible to prompt the user to resolve the remaining names.

The PR_ANR restriction matches the value of the PR_ANR property against the display name in the ADRLIST structure. Limiting the view of a container's contents table with the PR_ANR property restriction causes the address book provider to perform a "best guess" type of search, matching against the property that makes sense for the provider. For example, one address book provider might always match names in the recipient list against PR_DISPLAY_NAME while another might allow an administrator to select the property.

To set a PR_ANR property restriction on an address book container's contents table
  1. Create an SRestriction structure as shown in the following code:
    SRestriction SRestrict;

SRestrict.rt = RES_PROPERTY;
SRestrict.res.resProperty.relop = RELOP_EQ;
SRestrict.res.resProperty.ulPropTag = PR_ANR;
SRestrict.res.resProperty.lpProp->ulPropTag = PR_ANR;
SRestrict.res.resProperty.lpProp->Value.LPSZ = lpszName;
  2. Call the contents table's IMAPITable::Restrict method, passing the SRestriction structure as the lpRestriction parameter.


Expanding Distribution Lists

To prompt MAPI to expand a distribution list
  • Set its PR_ADDRTYPE property to MAPIPDL.

    MAPI expands addresses with this type before sending the message to the transport provider.


Handling a Transport Provider

Clients communicate with transport providers through status objects supplied by transport providers and the MAPI spooler. Clients access status objects by calling IMAPISession::GetStatusTable to retrieve the status table. Status objects implement the IMAPIStatus interface, which has methods for configuring providers, flushing incoming and outgoing message queues, setting passwords, and state validation. For more information about status objects, see Using the Status Table and Status Objects.


Message and Recipient Options

Transport providers maintain two groups of properties known as message and recipient options. Message options are properties that affect the transmission of particular messages. Some of the message options can be used to alter the folder contents table display. For example, if each message in the folder has a setting for PR_IMPORTANCE or PR_SENSITIVITY, the settings can be handled differently. Messages with high importance might be bold while less important messages might appear in normal text. Messages that are extremely confidential might only appear after explicitly searching for them.

Some of the commonly supported message options include:

Message option | Description
PR_SECURITY | To request additional security. Can be set to SECURITY_SIGNED or SECURITY_ENCRYPTED.
PR_PRIORITY | To establish a priority for delivery. Can be set to PRIO_URGENT, PRIO_NORMAL or PRIO_NONURGENT
PR_IMPORTANCE | To indicate a level of importance.
PR_SENSITIVITY | To indicate a level of privacy.
PR_DEFERRED_DELIVERY_ TIME | To specify when a message should be delivered.
PR_EXPIRY_TIME | To specify a time limit for message delivery.
PR_LATEST_DELIVERY_TIME | To specify the latest time when a message can be delivered.

Recipient options are properties that affect the processing of particular recipients. Recipient and message options affect a message after it has been submitted and usually correspond to a particular address type.

Default values for message and recipient options are established when MAPI calls a transport provider's IXPLogon::RegisterOptions method. Transport providers specify the properties in an array of property value structures included in the OPTIONDATA structure pointed to by the lppOptions parameter. Transport providers can register recipient options only, message options only, or both types of options.

You can retrieve the most current settings for the recipient option properties by calling either IAddrBook::RecipOptions or IAddrBook::QueryDefaultRecipOpt. RecipOptions displays a property sheet with the recipient option properties; QueryDefaultRecipOpt retrieves a property value array containing the settings.

Similar methods exist for retrieving the current message option properties. You can call IMAPISession::MessageOptions to allow users to view and change the settings and IMAPISession::QueryDefaultMessageOpt to retrieve the settings in a property value array.

Most transport providers supply a property sheet for displaying option properties. Some transport providers also allow users to make changes.


Sending or Receiving a Message on Demand

Clients typically rely on the MAPI subsystem — the MAPI spooler and the service providers — to handle the timing of message transmission and reception. However, you can alter this timing by using the status object of either the MAPI spooler or a transport provider. The IMAPIStatus::FlushQueues method removes all messages from one or more transport provider's incoming or outgoing queues. The following procedures describe two techniques for sending or receiving messages on demand. The first procedure uses the MAPI spooler's status object to flush the queues of every transport provider in the profile; the second procedure flushes the queue of a single transport provider.

To flush all incoming or outgoing queues in a single operation
  1. Call IMAPISession::GetStatusTable to access the status table.
  2. Call the status table's IMAPITable::SetColumns method to limit the column set to PR_ENTRYID and PR_RESOURCE_TYPE.
  3. Build a property restriction using an SPropertyRestriction structure to match PR_RESOURCE_TYPE with MAPI_SPOOLER.
  4. Call HrQueryAllRows, passing in the SPropertyRestriction structure, to retrieve the row that represents the status of the MAPI spooler.
  5. Pass the PR_ENTRYID column to IMAPISession::OpenEntry to open the MAPI spooler's status object.
  6. Call the MAPI spooler's IMAPIStatus::FlushQueues method, passing the FLUSH_NO_UI flag to suppress the user interface and either the FLUSH_DOWNLOAD or FLUSH_UPLOAD flag to flush the outgoing or incoming queues.
  7. Release the status object and the status table, as well as the SRowSet structure that is allocated for the table.
To flush incoming or outgoing queues individually by transport provider
  1. Call IMAPISession::GetStatusTable to access the status table.
  2. Call the status table's IMAPITable::SetColumns method to limit the column set to PR_ENTRYID and PR_RESOURCE_TYPE.
  3. Build a property restriction using an SPropertyRestriction structure to match PR_RESOURCE_TYPE with MAPI_TRANSPORT_PROVIDER.
  4. Call HrQueryAllRows, passing in the SPropertyRestriction structure, to retrieve the rows that are supplied by transport providers.
  5. For each row returned from HrQueryAllRows:
    1. Pass the PR_ENTRYID column to IMAPISession::OpenEntry to open the transport provider's status object.
    2. Check that the transport status object supports the FlushQueues method by checking that its PR_RESOURCE_METHODS property has the STATUS_FLUSH_QUEUES flag set.
    3. If supported, call IMAPIStatus::FlushQueues. If unsupported, call the MAPI spooler's IMAPIStatus::FlushQueues method, passing the entry identifier of the transport in the lpTargetTransport parameter. See the preceding procedure for instructions on accessing the MAPI spooler's status object. Set the FLUSH_DOWNLOAD flag to flush the outgoing queues or the FLUSH_UPLOAD flag to flush the incoming queues.
    4. Release the status object and the status table, as well as the SRowSet structure that is allocated for the table.

The MAPI spooler honors the FLUSH_NO_UI flag as do most LAN transport providers. However, not all transport providers honor this flag, particularly those that use a modem explicitly and the Remote Access Service (RAS). RAS was not designed to allow clients to suppress the user interface. It is possible for a client to be configured so that it can connect without requiring the interaction of a user, but it is difficult and requires intimate knowledge of the client's message services.


Setting Transport Order

The MAPI spooler assigns responsibility for outgoing messages based on the address types and identifiers that transport providers declare they can handle. Transport providers publish a list of supported address types and identifiers — stored in MAPIUID structures — when MAPI calls their IXPLogon::AddressTypes method, directly after logon. A recipient's address type is stored in its PR_ADDRTYPE property.

Registering for an address type indicates to MAPI that the transport provider can deliver to recipients with their PR_ADDRTYPE property set to the registered address type. Similarly, registering for a MAPIUID indicates that the transport provider can deliver to recipients that are represented by entry identifiers with the registered MAPIUID.

Most transport providers register for one or more address types; few register by MAPIUID. Transport providers that are tightly coupled with an address book provider and understand its entry identifier format can register to handle messages by MAPIUID, thereby improving performance. These tightly coupled transport providers can extract the recipient's e-mail address and other necessary information from the entry identifier without having to open it with an IMAPISupport::OpenEntry call.

MAPI maintains an order for transport providers, used when multiple transport providers have registered for the same address type or MAPIUID. You can override this order by:

  • Calling IMsgServiceAdmin::MsgServiceTransportOrder and passing an ordered list of the MAPIUIDs of all of the active transport providers pointed to by the lpUIDList parameter.
  • Using the Delivery property page of the Control Panel applet.

To retrieve a list of all of the address types that can be handled by one of the active transport providers, call IMAPISession::EnumAdrTypes. EnumAdrTypes returns an array of strings that describes address types supported by the transport providers that are active in the current session.


Reconfiguring a Transport Provider

You can use a transport provider's status object to change some of the properties of the provider. The range of properties that can be changed depends on the properties that are included with the provider's property sheet and how those properties are defined.

To reconfigure an active transport provider
  1. Call IMAPISession::GetStatusTable to access the status table.
  2. Locate the row for the transport provider to be reconfigured by creating a property restriction that matches PR_DISPLAY_NAME with the name of the target provider.
  3. Call IMAPITable::FindRow to retrieve the appropriate row.
  4. Check that the STATUS_SETTINGS_DIALOG and STATUS_VALIDATE_STATE flags are set in the target transport provider's PR_RESOURCE_METHODS property.

    If STATUS_SETTINGS_DIALOG is not set, the transport provider does not display a configuration property sheet. If STATUS_VALIDATE_STATE is not set, you cannot perform dynamic reconfiguration.

  6. If STATUS_SETTINGS_DIALOG is set, call IMAPIStatus::SettingsDialog to display the transport provider's property sheet and allow the user to make changes.
  7. After the user has finished with the reconfiguration, call IMAPIStatus::ValidateState if STATUS_VALIDATE_STATE is set, passing CONFIG_CHANGED.


Handling Notifications

Notifications enable one object to inform another object that it has undergone a change. The type of change is referred to as an event. MAPI defines several events for which notifications are generated. Clients typically register for one or more events with one or more objects. These objects are referred to as advise sources. Objects that can act as advise sources include the session object, under MAPI's control, or an object created by a service provider, such as a message. The informed object, referred to as the advise sink, contains either an implementation of the IMAPIAdviseSink interface or the IMAPIViewAdviseSink interface and is within a client application.

Advise source objects implement an Advise method, which is called by clients to register for notifications, and an Unadvise method, which is called to cancel a registration. One of the parameters to Advise is a pointer to an implementation of IMAPIAdviseSink or IMAPIViewAdviseSink. The advise source caches this pointer so that it can call IMAPIAdviseSink::OnNotify or one of the methods in IMAPIViewAdviseSink when a change occurs.

Because receiving notifications enables users to view the most up-to-date information, it is recommended that all clients register for and handle notifications. However, it is optional.


Registering for a Notification

A client can register for address book or message store notifications as part of its initialization process. MAPI supports notification on the address book regardless of whether any of the address book providers support it. Support for notification on message stores depends on the particular message store provider. To determine whether a particular message store provider supports notifications, check its PR_STORE_SUPPORT_MASK property. If the message store supports notifications, the STORE_NOTIFY_OK bit will be set.

Register for notifications by calling an advise source object's Advise method. Many objects implement Advise and clients can register with those objects in a variety of ways.

To register for a notification
  1. Create a MAPI advise sink object and increment its reference count.
  2. If appropriate, call HrThisThreadAdviseSink to create an advise sink object that wraps your original advise sink.
  3. Release the original advise sink.
  4. Call one of the following Advise methods to complete the registration:
    • Call IMAPISession::Advise to register for session notifications or for notifications on an address book or message store object.
    • Call IAddrBook::Advise to register for address book notifications or for notifications on a messaging user, container, or distribution list.
    • Call IABLogon::Advise to register directly with an address book provider for notifications on a messaging user, container, or distribution list.
    • Call IMsgStore::Advise to register for message store notifications or for notifications on a folder or message.
    • Call IMSLogon::Advise to register directly with a message store provider for notifications on a folder or message.
    • Call IMAPITable::Advise to register for table notifications.
  5. Cache the connection number returned from Advise.
  6. If using a wrapped advise sink, release it. Once the wrapped advise sink is registered, you no longer need it.

Calling IMAPISession::Advise enables you to register for critical error notifications on the overall session or for various notifications on individual objects. Sessions send critical error notifications to clients logged on to shared sessions when another client using the shared session calls MAPILogoff. To register for session notifications, pass NULL for the entry identifier parameter. To register for notifications on an individual object, pass the object's entry identifier. The IMAPISession method forwards the call to the appropriate service provider, as determined by the MAPIUID portion of the entry identifier. Calling IMAPISession::Advise to register for object notifications is simpler than calling a service provider's Advise method.

Registering with the address book is similar to registering with the session. To register for critical error notification from the address book, pass NULL for the entry identifier. To register for notifications on a particular address book object, specify the appropriate entry identifier and event or events of interest. Be aware that many address book providers do not support notifications on individual objects. Rather, they support table notifications on their contents and hierarchy tables.

It is good practice to release the advise sink that you implement or create with HrAllocAdviseSink immediately after a successful return from an Advise call. This is because it is possible for service providers to release your advise sink after the Advise call, but before an Unadvise call is made. Once you have given the advise source a pointer to your advise sink and the reference count has been incremented on this advise sink, it is wise to release it unless you have a long term use for it.

Note All connection numbers that represent valid advisory registrations will not be released until the Unadvise call is made.


Canceling a Notification

To cancel a notification, clients call an advise source's Unadvise method. Calling Unadvise is important because it causes the service provider to release its reference to your advise sink. As long as a service provider maintains a reference to an advise sink, the advise sink can continue to receive IMAPIAdviseSink::OnNotify calls. In fact, because of the asynchronous nature of event notification, clients can be notified even after a successful Unadvise call. Clients must be able to handle the receipt of notifications at any time.

Because service provider implementations differ, clients that fail to call Unadvise to cancel a notification cannot assume anything about when a provider will release its reference to their advise sink. Some service providers release their references to advise sinks when they release their advise sources. Some service providers do not. As long as a service provider maintains a reference to an advise sink, that advise sink can continue to receive notifications.


Handling Message Store Notification

To register for message store notifications, call either the IMAPISession::Advise or IMsgStore::Advise method and specify a message store, folder, or message entry identifier in the contents of the lpEntryID parameter. Message store providers support both object and table notifications. Whether you register with particular message store objects, with the folder hierarchy and contents tables that describe these objects, or with both objects and tables depends on the notifications you expect to see, the calls you make to perform operations, and how the message store provider supports notification.

Because MAPI allows flexibility in how providers support notifications, be aware that you will not always receive the same type of notification in response to a particular event from all message store providers. Some message store providers do not support notifications at all. To determine if the message store you are using supports notification, look for the STORE_NOTIFY_OK bit in its PR_STORE_SUPPORT_MASK property.

At one end of the spectrum of message store providers that support notification are the providers that generate "rich" notifications; these providers send descriptive notifications for all registered advise sources. At the other end are the message store providers that support limited notifications; these providers send general notifications for a restricted number of advise sources.

For example, if you copy a message to a folder with which you have registered to receive both object copied and object moved notifications, you may or may not receive the object copied notification. Whether or not you receive it depends on:

  • The method that you called to perform the copy. This could be IMAPIFolder::CopyMessages, IMAPIProp::CopyTo, or IMAPIProp::CopyProps.
  • How the message store provider implements the copy method.
  • Whether or not the message store provider supports object copied notifications on folders.

Because there are no strict guidelines that describe how to implement event notification for message store providers, clients cannot expect consistent behavior. MAPI does make recommendations as to how message store providers implement event notification and the following table outlines these recommendations. Read the table as follows: after you perform the operation in the first column, expect to receive a notification of the type listed in the second column if you have registered for that type with the object listed in the third column. For example, after you have created a folder, you will receive an fnevObjectCreated notification only if you have registered for fnevObjectCreated notifications with the message store.

Operation | Event type | Advise source
Create a folder | fnevObjectCreated | Message store
Delete a folder | fnevObjectDeleted | Message store Deleted folder
Move a folder from one folder to another | fnevObjectMoved | Message store Moved folder
Copy a folder from one folder to another | fnevObjectCopied | Message store and copied folder (no fnevObjectCreated notification sent for the new copy of the folder)
Change in a computed folder property (PR_SUBFOLDERS, PR_CONTENT_UNREAD, PR_CONTENT_COUNT) | fnevObjectModified | Message store Changed folder (No notification to parent folder)
Create a message | fnevObjectCreated | Message store
Delete a message, causing a change in the parent folder's PR_CONTENT_COUNT property | fnevObjectDeleted | Message store Deleted message
Move a message from one folder to another | fnevObjectMoved | Message store Moved message
Copy a message from one folder to another | fnevObjectCopied | Message store Copied message (No fnevObjectCreated notification for new copy of the message)
Save a message, causing a change in the parent folder's PR_CONTENT_COUNT property | fnevObjectCreated | Message store on first save only
Save a message | fnevObjectModified | Message store on saves after the first save Changed message (No notification to parent folder)
Complete a search operation | fnevSearchComplete | Message store Search folder
New message | fnevNewMail | Message store

Note When you receive an object modified notification, remember that the property tag array portion of the OBJECT_NOTIFICATION structure pointed to by the lpNotifications parameter in the OnNotify call may or may not be NULL. Message store providers are not required to insert property information in this array and most do not. Make sure your OnNotify method can handle the case where the lpPropTagArray pointer is NULL.

For most, if not all object notifications, update the view of the affected folder or folders.


Handing Address Book Notification

Address book notifications allow a client to learn of events that occur to any address book entry or to a particular entry. You can register for these notifications either through the MAPI address book by calling IAddrBook::Advise or through an address book container's hierarchy or contents table by calling IMAPITable::Advise.

Specify the entry identifier of an address book container, distribution list, or messaging user if you are registering for notifications on a particular entry and NULL if registering for notifications on the entire address book. The entry identifier must represent a messaging user or distribution list in an address book container. IAddrBook::Advise examines this entry identifier to determine which address book provider is responsible for the corresponding object and forwards the call to the appropriate address book provider's IABLogon::Advise method.

Clients can register for the following types of events on address book entries:

  • Critical error
  • Any of the object events (created, modified, deleted, moved, or copied)
  • Table modified

Typically, registration occurs only on address book container contents and hierarchy tables. It is rare that clients register with the lower level messaging user and distribution list objects. This is because:

  • Many address book providers do not support notifications on their messaging users and distribution lists.
  • Table notifications are sufficient for tracking changes and reporting them to users.


Handling Table Notification

As an alternative to registering directly with an advise source object, such as a folder or a messaging user, a client can register for notifications on a contents or hierarchy table. Tracking changes to address book entries, folders, and messages through a contents or hierarchy table can be simpler and more straightforward than through individual objects. For example, you can call IMAPITable::Advise on a folder's hierarchy table to discover when changes occur to one of its subfolders. If you support the viewing of remote messages, register with the status table to observe activity by transport providers and the MAPI spooler.

However, it is not always preferable to use table notifications instead of object notifications. Monitoring changes in the number of messages in a folder is an example of when your client might need to register for object notifications on a folder rather than on a table implemented by the folder.


Implementing an Advise Sink Object

A client can either implement it's own advise sink objects or use a utility function, HrAllocAdviseSink. HrAllocAdviseSink creates an advise sink object with an implementation of OnNotify that invokes a callback function.

There are advantages and disadvantages to using HrAllocAdviseSink. It can save work, but it provides no control over reference counting the advise sink object that it creates. Therefore, clients that need to carefully control their advise sink's release or that have interdependencies between their advise sink and another client object should construct their own IMAPIAdviseSink implementation and avoid using HrAllocAdviseSink altogether.

A client implementing its own advise sink should make it an independent object not related to or dependent upon any other objects so as to eliminate potential complications in reference counting and object release. However, if you must implement your advise sink as part of another object or include a back pointer to another object as a data member, it is recommended that two separate reference counts be maintained: one for the object referenced by the advise sink and one for the advise sink.

When the reference count of the referenced object falls to zero, all of its methods can fail and its vtable can be destroyed, but the memory for the advise sink must remain intact until after its reference count also falls to zero. This means that the advise sink's Release method must decrement its reference count and finish destroying the object when that count reaches zero. If two separate reference counts are not maintained, it would be easy to inadvertently destroy the advise sink as part of the encompassing object's Release process.

Clients using HrAllocAdviseSink to implement an advise sink must be equally careful not to include their callback function as a method in another advise sink object. For C++ clients, it is tempting to do this and pass the this pointer as a parameter. This is a dangerous strategy because clients typically free an object when its reference count reaches zero. Freeing the memory for the advise sink object would render the this pointer invalid.

Depending on the type of event and the advise source, your OnNotify method can handle events in various ways. The following table offers suggestions in how to handle some of the standard events.

Type of event | Handling in OnNotify
Object moved | If the moved object's original parent is related to the new parent, update the view beginning with the folder or address book container highest in the hierarchy. If the two parent containers are unrelated, update both of their views.
New message | Change the user interface to inform the user of the arrival of one or more new messages. Place the receive folder in the current view.
Error | For all objects except the session, log the error if necessary and return. For the session object, log off if possible.
Search complete | No processing necessary.

Note Notification handlers must be reentrant if they explicitly yield control of the computer.


Timing a Notification

Because event notification is an asynchronous process, you can be notified at any time, not necessarily immediately after the event has occurred. The timing of calls to your IMAPIAdviseSink::OnNotify method varies depending on the service provider implementing the advise source. Service providers can notify your client either:

  • Simultaneously with the event.
  • Directly after the event.
  • At some later point following the event, possibly after an Unadvise call.

Most service providers call OnNotify after the MAPI method responsible for the event has returned to its caller. For example, notifications on messages are sent either when changes to the message are saved, after the IMAPIProp::SaveChanges call, or when the message is released, after the IUnknown::Release call. Until the notification is sent, no changes are visible in the message store.

You can receive notifications from an advise source after you have called Unadvise to cancel a registration. Be sure to release your advise sink only after its reference count has fallen to zero, not following a successful Unadvise call. Do not assume that because you have called Unadvise that the advise sink is no longer necessary.


Ensuring a Thread-Safe Notification

If your client runs on a multithreaded platform such as Windows NT, you may need assurance that calls to your IMAPIAdviseSink::OnNotify methods occur on a particular thread. Because calls to OnNotify can typically occur on any thread, it is possible to receive notifications on unexpected and unwanted threads, leading to errors that are difficult to debug.

To guarantee that calls to OnNotify for a particular notification are made on the same thread that was used for the Advise call, call HrThisThreadAdviseSink before calling Advise. HrThisThreadAdviseSink creates a new advise sink object from your advise sink object. Pass this new object in the call to Advise. All clients with advise sink objects that might not work outside the context of a particular thread should always register advise sink objects created with HrThisThreadAdviseSink.

If your client runs on a 16-bit platform, you can call HrThisThreadAdviseSink if desired without any negative side effects; the only processing that occurs is an increment of the reference count on the original advise sink.


Forcing a Notification

When service providers use the IMAPISupport methods for notification, MAPI delivers notifications using a hidden window and its corresponding window procedure. For each process to receive a notification, MAPI posts a special message to the hidden window. This message is named with the constant szMAPINotificationMsg which is defined in MAPIDEFS.H.

You receive these notifications when the hidden window's window procedure processes the szMAPINotificationMsg message. To guarantee that notifications are delivered, it is necessary to wait for and dispatch this szMAPINotificationMsg message. Implementing the logic to achieve this can be done fairly simply, but MAPI provides an entry point into the MAPI(32) DLL called HrDispatchNotifications to make processing even simpler. Call HrDispatchNotifications as follows to receive notifications in your client:

HRESULT hr = HrDispatchNotifications(0);

Because the HrDispatchNotifications entry point was added as of MAPI version 1.0a, you might want to implement special logic if your client code predates this version. This special logic would bind dynamically to HrDispatchNotifications entry point if it is available and use the following code if it is not available:

#include <mapiwin.h>
HRESULT (STDAPICALLTYPE FAR *pDispatchFn)(ULONG ulFlags);
HINSTANCE hInst;
HRESULT hr;

hInst = GetModuleHandle("MAPI"szMAPIDLLSuffix".DLL");
pDispatchFn = GetProcAddress(hInst, "HrDispatchNotifications");
if (pDispatchFn)
    hr = (*pDispatchFn)(0);


Handling MAPI Forms

A MAPI form is a viewer for a message of a particular class. Clients that allow their users to work with messages belonging to a variety of message classes must be written to handle a variety of MAPI forms. To handle multiple forms, clients implement a component known as a form viewer which contains three objects:

  • Message site object, which supports the IMAPIMessageSite : IUnknown interface
  • View advise sink, which supports the IMAPIViewAdviseSink : IUnknown interface
  • View context object, which supports the IMAPIViewContext : IUnknown interface

Each of these objects is used by a component called the form server which implements each form, handling its storage and the notifications generated by clients handling the view. One other component, the form library provider, implements a form manager. The form manager administers the form libraries, which store form server executable files. This administration includes loading the appropriate form server and handling the initial communication between the server and the client.

The following diagram shows the relationship between a client and the other parts of the MAPI form architecture:

If your client plans to handle MAPI forms, you will use the form manager's IMAPIFormMgr interface to perform five basic tasks:

  • Launch the appropriate MAPI form server when a message is opened or composed.
  • Display form servers' icons in the contents tables of folders.
  • Send and receive form notifications. See Sending and Receiving Form Notifications.
  • Allow users to install or remove form servers from form libraries. See Maintaining a Form Library.
  • Allow users to associate form servers with particular folders.

To access the form manager, call the MAPIOpenFormMgr function once during initialization.

For more information about MAPI forms, see Forms and Developing MAPI Form Servers.


Implementing a Form Viewer

A form viewer includes three objects: a message site, a view advise sink, and a view context. Each of these objects allows you to interact with a form server and its forms.

A message site is an object that implements the IMAPIMessageSite interface and assists form servers with tasks such as moving, saving, or deleting messages, creating new messages, or launching new form servers. Message sites are used by forms to get information about your client's status with respect to various service providers. For example, a form can use your message site to get a pointer to your current message store, a message, or a folder.

There are two types of methods in the IMAPIMessageSite interface:

  • Methods that give information to form objects.
  • Methods that manipulate messages.

The methods that give information to form objects are straightforward to implement. In all cases except IMAPIMessageSite::GetSiteStatus, you should already have available the information required by each method.

The methods that manipulate messages should act as if they had been triggered through your regular user interface. For example, if a form object calls your IMAPIMessageSite::NewMessage method, behave as if the user had chosen to compose a new custom message with your regular user interface. Commands which typically generate this behavior are Compose, Open, Reply, Reply to All Recipients, Forward, Print, and Save As.

A view context is an object that implements the IMAPIViewContext interface and provides form servers with a context for the current message, allowing servers to easily switch to the next or previous message in the folder. A form uses a view context for sharing information. With a view context object, a form can:

  • Register with your client for notifications.
  • Activate the next or previous message in the folder.
  • Get printing information.
  • Get your client's status.
  • Get a stream that can be used to save the text version of a message.

Similar to the methods in the IMAPIMessageSite interface, the methods in IMAPIViewContext correlate with user actions and client features that relate to the view context. For example, a view context is involved with activating the next or previous message, sorting the contents of the folder, and filtering the contents of the folder.

It is not important what mechanism you provide for users to activate these features, such as from a button bar or from menu commands; it is only important that the semantics of those features map well to the methods in the IMAPIViewContext interface.

A view advise sink is an object that implements the IMAPIViewAdviseSink interface and handles notifications from form servers that affect your viewer and help forms and form viewers to work together. See Sending and Receiving Form Notifications for more information.


Implementing Standard Form Verbs

MAPI defines a set of standard verbs, or actions taken when a user makes a menu selection or clicks a button, that all form viewers should support. Each verb has a constant associated with it for identification, defined in the EXCHFORM.H header file. The following table lists the standard form verbs and their associated constants:

Verb | Value
Open | EXCHIVERB_OPEN
Reply | EXCHIVERB_REPLYTOSENDER
Reply to All | EXCHIVERB_REPLYTOALL
Forward | EXCHIVERB_FORWARD
Print | EXCHIVERB_PRINT
Save As | EXCHIVERB_SAVEAS
Reply to Folder | EXCHIVERB_REPLYTOFOLDER

When a user chooses a verb, pass its constant in a call to the form's IMAPIForm::DoVerb method to perform its corresponding action.

In addition to accessing verbs through your form viewer, users can sometimes access verbs directly from the form. For example, some form objects allow the user to invoke the Print verb by right-clicking on the form and choosing Print from a context-sensitive menu.

For compatability with Microsoft Mail 3.x, some reserved verbs are also defined. These verbs have constants that start with EXCHIVERB_RESERVED. These should not be passed to DoVerb, although future versions of MAPI may make use of them.


Sending and Receiving Form Notifications

Form notifications are used in MAPI to facilitate communication both from the form to your viewer as well as from your viewer to the form.

Forms send notifications to your viewer when one of the following events occur:

  • The form is closed.
  • A new message is loaded in the form.
  • Printing status changes.
  • A save operation is completed.
  • A message is sent.

Each of these event types correspond to a particular method in IMAPIViewAdviseSink, one of the interfaces that your form viewer must implement. When an event occurs, the form calls the corresponding IMAPIViewAdviseSink method in your viewer's advise sink. For example, when a new message arrives that your viewer should include in its display, the form calls your IMAPIViewAdviseSink::OnNewMessage method.

Implement your view advise sink in a way that makes sense for your viewer; there is no standard implementation. For example, in OnNewMessage you can update the view of the current folder's contents table to include the newly arrived message. In IMAPIViewAdviseSink::OnSubmitted, the method that is called when you receive a submitted message event, you can copy the submitted message to a Sent Items folder.

Forms receive notification from your viewer when a change occurs that affects the form and when you are loading a new message. To notify a form, call one of the methods of IMAPIFormAdviseSink: OnChange or OnActivateNext. Call OnChange to communicate status. For example, if the form is displaying the last item in a folder when a new message arrives, call OnChange with the VCSTATUS_NEXT flag set to tell the form that there is now a next item.

Call OnActivateNext to alert the form to the arrival of a new message that it may or may not be able to display. Pass the message class of the message to OnActivateNext.

Notifications by a form object to the client application are handled by the client application's IMAPIViewAdviseSink interface. See IMAPIViewAdviseSink : IUnknown for details.


Maintaining a Form Library

A form library holds all of the important information about a form: its properties, its verbs, and its server's executable files. Some clients allow their users to maintain, install, or remove form servers. If you want to offer this feature to your users, you must have access to:

  • The form server's configuration file, a file with the .CFG extension.
  • The form library's container object, an object that implements the IMAPIFormContainer : IUnknown interface.

To access the configuration file or a pathname to it, use whatever means are convenient. Usually, clients present the user with a dialog box for installing and removing form servers that can also be used to prompt the user for the location of the configuration file.

To access the form library's container, call the form manager's IMAPIFormMgr::OpenFormContainer method. Pass in an enumeration value to specify which form library to open, and if necessary, a pointer to the object that the form manager should use to open the form library. For example, if you are opening a folder form library, pass an IMAPIFolder pointer.

After OpenFormContainer returns the IMAPIFormContainer pointer, call either IMAPIFormContainer::InstallForm or IMAPIFormContainer::RemoveForm, depending on the maintenance to be performed. InstallForm adds a form server to the library; RemoveForm deletes a form server from the library.


Loading a Message Into a Form

To load an existing message into a form using a form server, use one of the following strategies.

  • Call IMAPISession::PrepareForm to create a token and then IMAPISession::ShowForm to display the form.
  • Call IMAPIFormMgr::LoadForm.

Using the PrepareForm and ShowForm strategy is comparatively easy, but it results in forms that are modal with respect to your client. This is because the call to ShowForm does not return until the form has exited. If you need to handle forms asynchronously, do not use this strategy.

Using the LoadForm strategy is more difficult because the method requires several parameters. These parameters instruct the form manager to launch the proper form server in the proper context and display the proper message. If the form server is already running, the form manager loads the message into the form server without launching a new instance of the form server.

To specify which form server to launch, pass the message class handled by the target server in the contents of the lpszMessageClass parameter. The appropriate message class can be determined by retrieving the PR_MESSAGE_CLASS property of the message to be loaded. Sometimes there is no form server for the specified message class, only a form server that handles messages belonging to the message's superclass. If you prefer that the message be loaded only by a form server specifically meant to handle messages of that class, set the MAPIFORM_EXACTMATCH flag in the LoadForm call. For more information, see Message Classes.

LoadForm also requires a pointer to your viewer's message site and view context and the value for the target message's PR_MSG_STATUS and PR_MESSAGE_FLAGS properties.


Composing a New Message Using a Form

To use a form to compose a new message, first create a new custom message object.

To compose a new message using a form
  1. Call the form manager's IMAPIFormMgr::ResolveMessageClass method to retrieve a pointer to a form information object — an object that implements the IMAPIFormInfo interface.
  2. Pass the pointer to the form information object in a call to IMAPIFormMgr::CreateForm. CreateForm loads the appropriate form server. In addition, pass an interface identifier to CreateForm to specify the interface to be used to access the new message. Typically, you request IPersistMessage by passing IID_IPersistMessage to CreateForm.
  3. Save the new message by calling its IPersistMessage::Save method. The form server should set values for the message's required properties when it creates the message.
  4. Load the message by using one of two strategies: IMAPIFormMgr::LoadForm or IMAPISession::PrepareForm followed by IMAPISession::ShowForm. For more information about these strategies, see Loading a Message Into a Form.

Note There are opportunities for performance gains when loading a new custom message into a form server because you will already have had an opportunity to get some information about the message — such as its message class — during the processing required for the ResolveMessageClass and CreateForm calls. Because of this, you will be able to simplify the processing required before calling LoadForm over that described in the topic Loading a Message into a Form .


Displaying Form Icons

When displaying a list of messages in a folder, it is helpful to your users if you distinguish messages with custom message classes from the standard IPM.Note messages. Custom message classes correspond to form servers, and form servers provide icons to represent themselves. You can display these icons in the list of messages to alert users to each message's message class before the user opens the messages. Typically, the icon in the form's PR_MINI_ICON property is the one that should be displayed in the list of messages. Forms also have a PR_ICON property that can be displayed when the form is minimized in a property sheet.

To get an icon for a message class without activating the form server for that message class
  1. Call the IMAPIFormMgr::OpenFormContainer method to get a pointer to an IMAPIFormContainer interface.
  2. Call the IMAPIFormContainer::ResolveMessageClass method to get a pointer to an IMAPIFormInfo interface.
  3. Call the IMAPIFormInfo::MakeIconFromBinary method to get an icon handle.

The icon can then be displayed using standard Win32 or Win16 APIs.

Warning Once you have the icon for a message class, make every effort to cache that icon. Not caching icons severely affects the performance of client applications. When caching icons, be careful of the relationships between message classes and their subclasses. For example, if the IPM.Note.Meeting.Cancel message class happens to resolve back to IPM.Note, do not assume that all subclasses of IPM.Note should use the icon for IPM.Note.


Administering Profiles and Message Services

Profile and message service administration can involve creating new profiles, deleting old profiles, and modifying the contents of existing profiles by changing the message services and service providers contained within them. Not all clients support profile and message service administration as standard features. Some clients have nothing more to do with profiles than allow their users to select one at logon time.

If you support profile or message service administration, chances are you will use the following interfaces that are implemented by MAPI:

  • IMsgServiceAdmin to administer a message service in a profile, accessable through either IMAPISession::AdminServices or IProfAdmin::AdminServices. Messaging clients typically call IMAPISession while configuration clients, or clients that do not send or receive messages, call IProfAdmin. Whenever possible, call the IProfAdmin method because it does not cause the message service to be started.

    For more information about using the IMsgServiceAdmin interface, see the following topics:

    Configuring a Message Service

    Copying a Message Service

    Deleting a Message Service

  • IProfAdmin to administer a profile, accessable through the MAPIAdminProfiles function.

    For more information about using the IProfAdmin interface, see the following topics:

    Creating a Profile with Custom Code

    Copying a Profile

    Deleting a Profile

    Finding a Profile Name

    Setting a Default Profile

  • IProfSect to maintain the properties in a profile section, accessable through the IMAPISession::OpenProfileSection or IProviderAdmin::OpenProfileSection method.

    For more information about profile sections, see Profiles.

  • IProviderAdmin to administer the service providers in a message service, accessable through IMsgServiceAdmin::AdminProviders.

    For more information about using the IProviderAdmin interface, see Adding or Deleting Providers in a Message Service.

Be careful in your support of profile and message service administration. There are no safeguards to protect against adversely modifying a profile that is in use. MAPI can prevent you from deleting a profile in use, but cannot prevent you from deleting every message service in it. If you delete every message service in a profile, all of the service providers in these services will stop thereby causing unpredictable results to occur.

Note If your client must run unattended, perhaps as a background application or a Windows NT service, some special cautions apply. For more information, see Writing an Automated Client and Windows NT Service Client Applications.


Creating a Profile

A client can create a profile in one of three ways:

  • Invoke the Profile Wizard, an application that creates a profile by allowing the user to choose message services and service providers interactively. For more information, see Creating a Profile with the Profile Wizard.
  • Invoke the NEWPROF utility, a tool that creates a profile by using the values contained in a template file. For more information, see Creating a Profile with NEWPROF.
  • Write C or C++ code, often the best choice for noninteractive client applications which require a specific set of message services. For more information, see Creating a Profile with Custom Code.


Creating a Profile with the Profile Wizard

The Profile Wizard is a MAPI application that allows a user to create a profile in the easiest possible way. The Profile Wizard displays a series of dialog boxes which prompt the user to select message services and enter values for a few of the most essential configuration properties. For most of the other required properties, the Profile Wizard uses default values provided. To invoke the Profile Wizard, call LaunchWizard, a function based on the LaunchWizardEntry prototype.

The user can add only those message services and service providers to the new profile that support the Profile Wizard. Because each message service might require more properties to be set than the Profile Wizard can handle, be aware that if you use this approach, it is possible for one or more of the selected services or providers to be incompletely configured.


Creating a Profile with NEWPROF

The NEWPROF utility is a tool that creates a profile without user interaction. All of the configuration settings are contained in a template file, a file that is expected to have the .PRF extension. MAPI provides a default .PRF file called DEFAULT.PRF that lists the services implemented by Microsoft and is divided into the following four sections, similar to the sections in a profile:

  • Section 1 includes the [General] section.
  • Section 2 includes the [Service List] section.
  • Section 3 includes sections that describe individual message services.
  • Section 4 includes sections that map to profile properties.

You can create a new .PRF file using portions of DEFAULT.PRF as a model or modify the DEFAULT.PRF file directly, adding portions that pertain to your profile and configuration. For each service you plan to use, copy the section that lists the name, type, and property identifier for each configuration property. The section must have the same name as the service.

To create a .PRF file
  1. Assemble information from existing .PRF files.
  2. Place the profile name in the ProfileName= line of the [General] section.
  3. Create the [Service List] section after the [General] section. In this section, list each message service that you require and the name of the section that contains its configuration properties. For information about ordering services in profiles, see Profiles.
  4. For each service listed in the [Service List] section, create an individual message section that lists the value for each configuration property. The section must have the same name as the service. See Section 3 in the DEFAULT.PRF file for an example.
  5. Invoke the NEWPROF utility. On 32-bit operating systems, NEWPROF can be run from a command line or batch file. On 16-bit Windows systems, NEWPROF cannot be run from an MS-DOS shell. Instead, run NEWPROF:
    • With a Windows-based setup script.
    • With the Run command on the File menu in Program Manager or File Manager.
    • With the WinExec system call.


Creating a Profile with Custom Code

If you choose to write code to create a profile, make sure that you understand how to order profile entries and the type and amount of information that is needed for each entry. The implications of ordering entries in a profile is explained in Profiles.

To create a profile with C or C++ code
  1. Read the header file for each message service. Understand what properties you will need to configure and what values you will use.
  2. Call the MAPIAdminProfiles function to retrieve an IProfAdmin interface pointer.
  3. Call IProfAdmin::CreateProfile to create your profile. If you want to create a profile with the message services listed in the [Default Services] section of the MAPISVC.INF file, set the MAPI_DEFAULT_SERVICE flag. If you want to allow the user to enter configuration information, set the MAPI_DIALOG flag. Make sure that you set this flag if not all of the necessary information is available through the MAPISVC.INF file. CreateProfile calls the entry point function for each message service to be added to the profile with MSG_SERVICE_CREATE set as the ulContext parameter.
  4. Call IProfAdmin::AdminServices to obtain a message service administration object.
  5. Use the message service administration object to add message services to the profile. For each message service that you want to add:
    1. Call the IMsgServiceAdmin::CreateMsgService method to create the new message service.
    2. Call IMsgServiceAdmin::ConfigureMsgService, passing the MAPIUID structure of the service you just created and a property value array with its configuration properties.
  6. To retrieve the identifier of a newly added service, its PR_SERVICE_UID property, call IMsgServiceAdmin::GetMsgServiceTable to access the message service table and search for the row that represents the message service. The last row in the table will represent the most recently added message service.

To make a new profile temporary, call the IProfAdmin::DeleteProfile method immediately after you log on. DeleteProfile will mark the new profile as deleted while making it usable for the duration of the session. Because it will not be included in the session's profile table, other clients will be unable to use it.


Copying a Profile

One way to create a profile is to copy from an existing profile and alter the necessary message services and service providers. Copying a profile involves using a profile administration object, provided by MAPI through the MAPIAdminProfiles function.

To copy a profile
  1. Call MAPIAdminProfiles to retrieve an IProfAdmin interface pointer.
  2. Call IProfAdmin::GetProfileTable to access the profile table.
  3. Build a property restriction with an SPropertyRestriction structure to match PR_DISPLAY_NAME with the name of the profile to be copied.
  4. Call IMAPITable::FindRow to locate the appropriate row in the profile table.
  5. Call IProfAdmin::CopyProfile, passing the value of the PR_DISPLAY_NAME column as the lpszOldProfileName parameter.


Deleting a Profile

To delete a profile
  • Call IProfAdmin::DeleteProfile.

DeleteProfile marks the profile for deletion if it is currently being used, waiting until it is no longer active to remove it. The profile does not actually disappear until every client with an active session has disconnected.

DeleteProfile calls the entry point function of every message service in the profile with the ulContext parameter set to MSG_SERVICE_DELETE. The calls to the entry point functions occur before the services are physically removed from the profile.


Setting a Default Profile

The default profile is the profile that is used if you do not explicitly specify one in the call to MAPILogonEx, setting instead the MAPI_USE_DEFAULT flag.

To establish a default profile
  1. Call the MAPIAdminProfiles function to retrieve an IProfAdmin interface pointer.
  2. Call IProfAdmin::SetDefaultProfile. SetDefaultProfile sets the PR_DEFAULT_PROFILE property for the new default profile and removes the setting for the previous default profile.


Finding a Profile Name

Clients sometimes need to find the name of the profile currently being used for the session, the name of the default profile, or the name of an alternate profile installed on the workstation.

There are a few ways to retrieve the name of a profile during the course of a session. If you need to find the name of a profile that is not necessarily the one being used for the session, use the first procedure. If you need to find the name of the default profile, use the second procedure. If you need to find the name of the current profile for the session, use one of the last two procedures.

To find the name of any profile
  1. Call MAPIAdminProfiles to retrieve an IProfAdmin interface pointer.
  2. Call IProfAdmin::GetProfileTable to access the profile table.
  3. Call the profile table's IMAPITable::QueryRows method to retrieve all of the rows in the table and examine each one to determine if it represents your target profile.
To find the name of the default profile
  1. Call MAPIAdminProfiles.
  2. Call IProfAdmin::GetProfileTable to access the profile table.
  3. Build a property restriction with an SPropertyRestriction structure to match PR_DEFAULT_PROFILE with the value TRUE.
  4. Call IMAPITable::FindRow to locate the row in the profile table that represents the default profile. The PR_DISPLAY_NAME column contains the name of the default profile.
To find the name of the current profile
  • Assuming that you have the MAPIUID structure representing one of the current profile's sections, pass it in the lpUID parameter to IMAPISession::OpenProfileSection. Retrieve the profile section's PR_PROFILE_NAME property using its IMAPIProp::GetProps method.

-Or-

  • Call IMAPISession::GetStatusTable to access the status table and find the row that has its PR_RESOURCE_TYPE column set to MAPI_SUBSYSTEM. The PR_DISPLAY_NAME column for this row is the profile name.

    Do not use the status table during start up because it blocks an application until the MAPI spooler has finished initializing all of the transport providers. This can degrade your performance.


Adding a Message Service

To add a new message service to a profile
  • Call IMsgServiceAdmin::CreateMsgService. CreateMsgService performs the following tasks:
    1. Copies all of the relevant information for the message service that is in the MAPISVC.INF file, creating a profile section for every provider section.
    2. Calls the message service's entry point function with the ulContext parameter set to MSG_SERVICE_CREATE.
      1. Sets the message service's PR_SERVICE_UID property.
To access the new message service
  1. Call IMsgServiceAdmin::GetMsgServiceTable to retrieve the message service table.
  2. Call the message service table's IMAPITable::Advise method to register for table notifications.
  3. When MAPI sends a TABLE_ROW_ADDED notification, locate the entry identifier of the newly added message service in the SRow structure included in the TABLE_NOTIFICATION structure.


Configuring a Message Service

To configure all the service providers in a message service
  • Call IMsgServiceAdmin::ConfigureMsgService.

    If all of the data necessary for configuration is available programmatically, you can choose whether or not to display a user interface. However, if some of the information for one or more providers is not available, make sure that you set the SERVICE_UI_ALLOWED or SERVICE_UI_ALWAYS flag. Suppressing a user interface when required configuration data is unavailable results in an unconfigured message service.

To configure a single service provider in a message service
  1. Call IMAPISession::GetStatusTable to access the service provider's status object.
  2. Call IMAPIStatus::SettingsDialog to display the service provider's property sheet.

For more information about using status objects, see Using the Status Table and Status Objects.


Copying a Message Service

To copy a message service to a profile
  1. Call IMsgServiceAdmin::CopyMsgService.

When a message service is copied, the new instance of the service is configured in exactly the same way as the original. Sometimes CopyMsgService returns the error MAPI_E_ACCESS_DENIED. The most common cause of this error return is a message service that does not allow itself to be duplicated.


Deleting a Message Service

To delete a message service from a profile
  1. Call IMAPISession::GetMsgServiceTable to access the message service table.
  2. Locate the row for the message service and pass its PR_SERVICE_UID column in the lpuid parameter to IMsgServiceAdmin::DeleteMsgService.

DeleteMsgService calls the message service's entry point function with the ulContext parameter set to MSG_SERVICE_DELETE. Message services perform any clean up tasks at this time before they are removed from the profile.


Adding or Deleting Providers in a Message Service

To add or delete service providers in a message service, use the IProviderAdmin interface. You can retrieve an IProviderAdmin pointer by calling IMsgServiceAdmin::AdminProviders. The provider table, accessable through IProviderAdmin::GetProviderTable, lists information about the service providers currently installed in the message service. Clients and service providers can use the provider table to access the name of the provider DLL file, for example, or the MAPIUID, display name, and type of the provider as well as information about the message service. See Provider Table for more information.

To add or delete a service provider in a message service
  1. Call the AdminServices method to access a message service administration object.
  2. Call IMsgServiceAdmin::GetMsgServiceTable to access the message service table.
  3. Build a property restriction using an SPropertyRestriction structure that matches PR_DISPLAY_NAME or PR_SERVICE_NAME with the name of the message service to be modified.
  4. Call the message service table's IMAPITable::FindRow method to locate the row in the table that represents the targeted message service.
  5. Call IMsgServiceAdmin::AdminProviders to retrieve an IProviderAdmin pointer. Pass the PR_SERVICE_UID column from the message service table row as the lpUID parameter.
  6. Call IProviderAdmin::GetProviderTable to access the provider table.
  7. Build a property restriction using an SPropertyRestriction structure that matches PR_DISPLAY_NAME or PR_PROVIDER_DISPLAY with the name of the service provider to be added or deleted.
  8. Call the provider table's IMAPITable::FindRow method to locate the row in the table that represents the targeted service provider.
  9. Call IProviderAdmin::CreateProvider to add the provider or IProviderAdmin::DeleteProvider to remove it from the message service. For CreateProvider, pass the provider's PR_DISPLAY_NAME property as the lpszProvider parameter. For either method, pass the provider's PR_SERVICE_UID property as the lpUID parameter. After the service provider has been added or deleted, the change will not be apparent until a new session is created.

Another technique for adding a service provider, specifically a message store provider, to a profile involves constructing an entry identifier for the provider. Because constructing an entry identifier requires knowledge of its format, this technique can only be used if the service provider has made its entry identifier format public.

With the newly constructed entry identifier, a client can call IMAPISession::OpenMsgStore. MAPI automatically creates a profile section in the profile for the service provider, but does not add it to a message service.

Some message services do not allow this type of dynamic modification; whether or not it is supported is up to the message service. Another feature that may or may not be supported is the ability to directly access a message service's private profile sections. If the message service you are using permits such access, it will publish the GUID that represents the private section in MAPISVC.INF. You can pass this GUID in a call to IProviderAdmin::OpenProfileSection to access the profile section.


Advanced Client Topics

This section includes subtopics on how to implement some of the more uncommon or difficult features in a client application.


Writing an Automated Client

An automated client application is an application that runs unattended, displaying no user interface. By default, many MAPI interface methods show a user interface. All of these methods have flags that allow a client to either allow or suppress this display. Although MAPI expects service providers to honor these flags, there are some providers that do not always meet these expectations. A legitimate reason for not honoring the flags is the reliance of the service provider on another service that does not allow user interface suppression. If you are developing an automated client, pay careful attention to the service providers you are using and how they are configured. Do not assume that all of your calls to suppress a user interface will be successful.

Automated clients must have the necessary information available for proper configuration of each of the message services in the profile. There are two ways to supply configuration information at logon time:

  • The service provider can retrieve information from the profile.
  • The service provider can prompt the user for information.

Since the second option is unavailable to automated clients, these clients must use the first option. Clients must configure their profiles carefully to ensure that this option always works.

Using a profile created previously for another purpose is allowable but will not work if the user has chosen not to cache credentials for one or more services. On Windows 95, caching credentials may not work due to password cache control. If the profile is created when the user is logged on to a network, and subsequently used when not logged on to a network, cached credentials will be unavailable.

Automated clients always set the MAPI_NO_MAIL flag in the MAPILogonEx function call to begin a MAPI session.


Writing a Remote Viewer

A remote viewer is a window in a client application that provides controlled access to messages stored on another computer. This controlled access might be with a modem or other type of slow link. Rather than retrieve a complete selection of available messages every time a user opens a folder, the remote viewer first displays only the headers. The user then selects from the headers which of the messages to display in full. Remote viewer clients can allow their users to delete messages before they are ever downloaded.

To retrieve the headers of messages stored remotely
  1. Call IMAPISession::GetStatusTable to access the status table.
  2. Call IMAPITable::Restrict to limit the status table to only those rows that have their PR_RESOURCE_TYPE column set to MAPI_TRANSPORT_PROVIDER.
  3. Call IMAPITable::SetColumns to include the following columns in the status table: PR_ENTRYID, PR_RESOURCE_METHODS, PR_RESOURCE_TYPE, PR_PROVIDER_DISPLAY, and PR_STATUS_CODE.
  4. Call HrQueryAllRows to retrieve all the rows in the status table.
  5. Pass the entry identifier for each row in the table in a call to IMAPISession::OpenEntry. Because this interface is marshaled from the MAPI spooler's process context to the client's process context — unlike interfaces typically obtained from address book or message store providers — issues concerning multithreading are of more importance.
  6. Call the status object's IUnknown::QueryInterface method, passing IID_IMAPIFolder as the interface identifier, to retrieve the remote folder.

    The remote folder is not a complete folder implementation; it supports only a subset of folder methods and properties. One of the required methods, IMAPIProp::GetProps, supports the retrieval of the following properties:

PR_ACCESS | PR_ACCESS_LEVEL
PR_CONTENT_COUNT | PR_ASSOC_CONTENT_COUNT
PR_FOLDER_TYPE | PR_OBJECT_TYPE
PR_SUBFOLDERS | PR_CREATION_VERSION
PR_CREATION_TIME | PR_DISPLAY_NAME
PR_DISPLAY_TYPE |

Remote folders must also support the IMAPIProp::GetPropList, IMAPIContainer::GetContentsTable, and IMAPIFolder::SetMessageStatus methods. Remote folder contents tables typically support the following columns:

PR_DISPLAY_TO | PR_ENTRYID
PR_HASATTACH | PR_IMPORTANCE
PR_INSTANCE_KEY | PR_MESSAGE_CLASS
PR_MESSAGE_DELIVERY_TIME | PR_MESSAGE_FLAGS
PR_MESSAGE_DOWNLOAD_TIME | PR_MESSAGE_SIZE
PR_MSG_STATUS | PR_OBJECT_TYPE
PR_NORMALIZED_SUBJECT | PR_PRIORITY
PR_SENDER_NAME | PR_SENSITIVITY
PR_SENT_REPRESENTING_NAME | PR_SUBJECT

  7. Call the transport provider's IMAPIStatus::ValidateState method the first time that one of the transfer options is picked. Either the REFRESH_XP_HEADER_CACHE or PROCESS_XP_HEADER_CACHE process flag should be set as well as the SHOW_XP_SSESSION_UI flag to allow the user interface to be shown.

Note To mark a particular message header for downloading or deletion, a client calls IMAPIFolder::SetMessageStatus and sets either the MSGSTATUS_REMOTE_DOWNLOAD or MSGSTATUS_REMOTE_DELETE flag.


Writing a Hierarchy Viewer

A hierarchy viewer is a user interface component that is used for displaying folder and address book container hierarchy tables. Hierarchy viewers can display members of the hierarchy at different levels, expanding and contracting each level on demand.

If you are using the 32-bit version of MAPI, you can implement your hierarchy viewer manually or with the standard tree control from COMCTL32.DLL.

The container property, PR_DEPTH, controls the level at which a hierarchy member is displayed. Entries that represent top-level address book containers or folders have their PR_DEPTH property set to zero. The value of this property is incremented sequentially for entries in sequential levels. That is, when a user selects a top-level container to expand, display all containers with PR_DEPTH set to 1. When a user expands one of these subcontainers, display the containers with PR_DEPTH set to 2, and so on.

Hierarchy viewers support a different range of depths. You can limit your viewer to only one or two levels or support multiple levels, if displaying an expansive hierarchy is a priority.

The address book provides a hierarchy viewer for the top-level containers in the address book.

To access the address book hierarchy viewer
  1. Call IAddrBook::OpenEntry, passing a null entry identifier, to open the address book's root container.
  2. Call the root container's IMAPIContainer::GetHierarchyTable method to access the hierarchy table of the MAPI address book.
To access the default message store's hierarchy viewer
  1. Call IMAPISession::GetMsgStoresTable to access the message store table.
  2. Build a restriction using the SPropertyRestriction structure to limit the table to only those rows that have a PR_DEFAULT_STORE property set to TRUE.
  3. Call IMAPITable::FindRow, passing it the SPropertyRestriction, to locate the row representing the default message store.
  4. Call IMAPISession::OpenEntry, passing in the PR_ENTRYID property from the default message store's row in the message store table.
  5. Call the message store's IMAPIProp::GetProps method to retrieve the PR_IPM_SUBTREE_ENTRYID property.
  6. Call the message store's IMsgStore::OpenEntry method, passing the PR_IPM_SUBTREE_ENTRYID property, to open the root folder of the message store's IPM subtree.
  7. Call the IPM root folder's IMAPIContainer::GetHierarchyTable method to access its hierarchy table.


Using the MAPI Utilities

The MAPI utilities are made up of table data and property data objects and a variety of functions to support miscellaneous features. It is possible for a client to need only these utilities and not have to log on to the MAPI subsystem to establish a connection with service providers. If your client fits into this category, call the API function ScInitMapiUtil rather than the MAPIInitialize function at initialization time.

ScInitMapiUtil enables clients to use utility functions that require MAPI allocators, but that do not ask for the allocators explicitly. When it is time to shut down, call DeinitMapiUtil to free resources rather than MAPIUninitialize. Clients that never call MAPIInitialize should not call MAPIUninitialize.

If you have called ScInitMapiUtil rather than MAPIInitialize and are using tables through the ITableData methods rather than through the IMAPITable methods, be aware that table notifications will not work. Notifications require the use of the MAPI libraries and IMAPITable.


Converting to Active Messaging Library Identifiers

Some clients use multiple client interfaces to take advantage of what more than one client API has to offer. Typically, these clients use MAPI for some tasks and a simpler API such as the Active Messaging Library for other tasks. If you take advantage of both the MAPI and the Active Messaging Library client interfaces, you will need to convert between the two types of identifiers that are used for opening objects. Whereas MAPI objects are accessed with binary entry identifiers, Active Messaging Library objects are accessed with hexadecimal message identifiers.

To convert a MAPI entry identifier to an Active Messaging Library message identifier
  1. Call the message's IMAPIProp::GetProps method to retrieve its PR_ENTRYID property.
  2. Call HexFromBin to convert the entry identifier to a hexadecimal string or use client code to perform the conversion.
  3. Call the Win32 function SysAllocString, if necessary, to make the string compatible with Visual Basic.
  4. Make the hexadecimal string available to the Visual Basic application.
  5. Use the Session.GetMessage method in the Active Messaging Library to open the message.

To reverse the process — converting an Active Messaging Library message identifier to a MAPI entry identifier — call FBinFromHex. FBinFromHex converts a hexadecimal string to binary data.


Implementing a Progress Indicator

Many of the operations initiated by clients take a significant amount of time. One of the input parameters to these potentially lengthy operations is a pointer to a progress object — an object that implements the IMAPIProgress interface. Progress objects control the appearance and display of progress indicators and are implemented by clients and by MAPI. You can choose whether or not to implement a progress object; the MAPI implementation is available for service providers to use if you elect not to supply an implementation.

Progress objects work with the following pieces of data:

  • A global minimum value which, when your IMAPIProgress::Progress method is called, should be less than or equal to the value of the ulValue parameter. At the beginning of the operation, ulValue will be equal to this minimum value.
  • A global maximum value which, when your IMAPIProgress::Progress method is called, should be greater than or equal to the ulValue parameter. At the end of the operation, ulValue will be equal to this maximum value.
  • A flags value which indicates whether the progress corresponds to a top or lower level item.
  • A value that indicates the current level of progress for the operation.
  • The number of the currently processed item relative to the total.
  • The total number of items to be processed during the operation.

The minimum and maximum values represent the beginning and end of the operation in numeric form. Use 0 for the initial minimum value and 1000 for the initial maximum value, passing these values to service providers in the IMAPIProgress::GetMin and IMAPIProgress::GetMax methods. Service providers reset these values when they call IMAPIProgress::SetLimits.

The flags value is used by service providers to determine how they should set the other values. Initialize the flags value to MAPI_TOP_LEVEL and return this value in your implementation of GetFlags until the service provider resets it by calling SetLimits.

In your implementation of the SetLimits method, save local copies of each of the parameters: lpulMin, lpulMax, and lpulFlags. These values should be readily available when a service provider calls your GetMin, GetMax, or GetFlags methods.

To update the display of the progress indicator, service providers call your IMAPIProgress::Progress method. There are three parameters to this method: a value, a count, and a total. Use the first parameter, ulValue, to display the progress indicator. The ulValue parameter is the progress indicator and will be equal to global ulMin only at the very beginning of the operation and equal to global ulMax only at the completion of the operation.

Use the second and third parameters, ulCount and ulTotal, if available, to display an optional message such as "5 items completed out of 10." If the second and third parameters are set to 0, you can choose whether or not to visually change the progress indicator. Some service providers set these parameters to zeroes to indicate that they are processing a subobject whose progress is monitored relative to a parent object. In this situation, it makes sense to change the display only when the parent object reports progress. Some service providers pass zeroes for these parameters every time.


Centralizing the Receipt of NDRs

To have nondelivery reports (NDRs) arrive at a central location when multiple instances of your client are running simultaneously
  1. Set PR_REPORT_ENTRYID, PR_REPORT_NAME, and PR_REPORT_SEARCH_KEY to the appropriate values for the account that is to receive the reports. Create the entry identifier by calling IAddrBook::CreateOneOff if necessary.
  2. Understand that there are messaging systems that will ignore the account you've requested for reports and send them to the originator. Reduce the impact that this will have on administrators that will need to move reports around by:
    • Giving your original message a distinct message class, such as IPM.Note.MSNNews. Look for incoming messages with class Report.IPM.Note.MSNNews.NDR and forward them to the account you intended reports to come to. At the same time, send e-mail to the messaging system that ignored your nondelivery report account to the affect that it should honor the PR_REPORT_ENTRYID property.
    • Most messaging systems which do not honor PR_REPORT_ENTRYID will not honor the MAPI message class conventions either. Therefore, you'll receive something that looks like a note. This is a little harder to deal with since the input is so variable. Look at the subject and forward it if you find either something from a list of words that mean "undeliverable" or something from your original subject.
    1. Be prepared to tune these lists over time.


Improving Client Performance

The following tips will help you create a client application with the best possible performance:

Avoid Certain Methods at Startup

Get and Set Multiple Properties

Use a Table to Work with Properties

Get and Set Properties with GetProps and SetProps

Save Frequently Used Properties

Defer Processing

Write Uncompressed Formatted Text

Avoid Using IStream::SetSize to Extend a Stream

Sort Tables after Setting Columns and Restrictions

Call QueryRows for Small Tables

Open OLE Attachments with IStreamDocfile

Name Folders with Character Strings


Avoid Certain Methods at Startup

To improve performance at startup time, avoid making the following calls:

IMAPISession::EnumAdrTypes | IMAPISession::Logoff
IMAPISession::GetStatusTable | IMAPISession::MessageOptions
IMAPISession::QueryDefaultMessageOpt | IMAPIStatus::ValidateState
IMAPISession::QueryIdentity | IUnknown::Release

The call to IMAPIStatus::ValidateState affects performance only when made on either the MAPI spooler or the MAPI subystem. The reason that these methods slow start up processing is because they cannot complete until the MAPI spooler has finished its startup tasks.

Another task to avoid at startup is searching the message store. Make your IMAPIContainer::SetSearchCriteria call when startup processing has finished.


Get and Set Multiple Properties

By getting and setting as many properties as possible with the least number of calls, remote activity is curtailed and the overhead involved with each property is reduced. Although service providers try to collect properties before making a remote procedure call for retrieval or modification, you can optimize this effort by requesting multiple properties to begin with.

For example, if you work with routing lists that describe future recipients with named properties belonging to particular property sets, process all of the recipients with two calls, one to IMAPIProp::GetIDsFromNames to retrieve the identifiers for all of the recipient properties and the other to IMAPIProp::GetProps to retrieve all of the values. The alternative, making a call to GetIDsFromNames followed by a call to GetProps for each recipient, is much less efficient.


Use a Table to Work with Properties

Many properties are available both from the objects that support them and as columns on tables. Whenever possible, retrieve these properties through the table. Call IMAPITable::SetColumns to include all of the properties that your client needs and IMAPITable::QueryRows to retrieve all of the rows of the table.

These two calls are usually sufficient for retrieving enough information to display to a user and frequently sufficient for any necessary internal processing, making a call to OpenEntry to open the object unnecessary.

There are only two exceptions:

  • If the property is over 255 bytes. The IMAPITable interface might not return the entire property value, instead truncating it at 255 bytes. Think about this tradeoff, though. If you are displaying this data to the user, 255 bytes may be enough for a textual field such as a comment.
  • If you need a specific property from a single row in a table. In this case it is unnecessary to create a table with properties that will never be used. Most of the time you will need the same properties for all rows.


Get and Set Properties with GetProps and SetProps

Whenever possible, try to retrieve or modify a property with the IMAPIProp::GetProps and IMAPIProp::SetProps methods. Unless the property you are working with is very large, these methods should be adequate. The other alternative is to read from or write to a stream with the OLE interface IStream. Streams can handle very large properties successfully, but they are a greater drain on resources because they require the OLE libraries. Use the IStream interface only after your call to IMAPIProp::GetProps or IMAPIProp::SetProps fails.


Save Frequently Used Properties

Improve performance by storing data that takes time and resources to retrieve and is accessed frequently. Using extra memory can sometimes be a better option that repeated retrievals. Use caution and care when creating a cache for storing this data. Keep in mind that a poorly designed cache can negatively impact performance.

For example, most IPM clients need to display and open the IPM subtree of folders many times during a typical session. You can improve performance by storing the entry identifiers for each of these folders.


Defer Processing

Pass the MAPI_DEFERRED_ERRORS flag to method calls as much as possible. Many of the MAPI method calls have been optimized to accept this flag, causing the provider to either postpone the requested task until multiple tasks can be performed at once or you can wait no longer for the results.

For example, if you pass MAPI_DEFERRED_ERRORS to IMsgStore::OpenEntry to open a folder, the opening of the folder and a possible remote call can be postponed until you make another call such as a call to the folder's GetHierarchyTable or GetProps methods. Both GetHierarchyTable and GetProps require the return of data from the service provider, a task that must be performed immediately.

Another way to defer processing is simply not to make a call. By being aware of the user and when the user can perceive a drain on resources or processing time, you can determine when it makes sense to make calls. There is an opportunity to improve performance by making calls either at a time when the user will not notice or not making them at all.

For example, consider the situation when you are receiving more than one notification per second from a message store that is moving a great number of messages. A progress indicator is displayed to indicate the percentage of the operation's completion. Users typically will not perceive this operation to be slow until a few seconds have passed. Therefore, if you are updating the progress indicator, do not make any changes until at least four seconds after the initiation of the move operation. This will save time in the common cases when the operation is fast and inform users in a timely manner when the operation is slow.


Write Uncompressed Formatted Text

When preparing to send a message with formatted text, either set the message's PR_RTF_COMPRESSED property to compressed or uncompressed text. Writing compressed text in the PR_RTF_COMPRESSED property is a very CPU intensive operation and can dramatically affect performance.

To improve the performance of sending formatted messages, either:

  • Upgrade the CPU, a solution that is not always plausible.

    – Or –

  • Write uncompressed text in the PR_RTF_COMPRESSED property.

The procedure for setting PR_RTF_COMPRESSED with uncompressed text is the same as for setting it with compressed text, with one exception. When calling WrapCompressedRTFStream, set the STORE_UNCOMPRESSED_RTF flag in the ulFlags parameter. Setting uncompressed text has the disadvantage in that it increases the size of messages.


Avoid Using IStream::SetSize to Extend a Stream

When writing to streams, it is sometimes necessary to enlarge them because their initial size is no longer sufficient. Use the OLE method IStream::Write to accomplish this rather than IStream::SetSize. IStream::Write automatically extends the stream, making IStream::SetSize unnecessary. Calling IStream::Write without IStream::SetSize can be up to three times faster than making the SetSize call prior to Write.


Sort Tables after Setting Columns and Restrictions

When you need to limit the view of a sorted table, always make the following IMAPITable calls in the following order:

  1. IMAPITable::SetColumns to define the column set.
  2. IMAPITable::Restrict to impose the restriction.
  3. IMAPITable::SortTable to perform the sort.

If the sorted table is categorized, make a call to SetCollapseState if necessary after the SortTable call. This ordering of calls is important because most service providers sort a table as the last task to achieve the best performance. If, for example, a message store provider must categorize a folder contents table before a restriction can be imposed, this categorization will be removed during the processing of the restriction. A second categorization will be necessary.


Call QueryRows for Small Tables

When retrieving rows from a small table, call IMAPITable::QueryRows instead of first building a restriction. Creating a restriction impacts performance because the provider must first create a table, find the matching rows in the original table, and then copy the rows to the new table. If the total number of rows in the table is less than one hundred, it is probably more effective to read all of the rows and then call IMAPITable::FindRow to find the appropriate row. This is a particularly good strategy if this information is needed only occasionally.

A proper time to use a restriction is when the restricted or filtered information will be used over a longer period of time or used frequently. For instance, if you always need a view with unread messages, then a restriction is the proper call to use.


Open OLE Attachments with IStreamDocfile

When opening an OLE object attachment, use the IStreamDocfile interface rather than IStream or IStorage. IStreamDocfile provides direct access to the object using structured storage, eliminating the need to perform a copy operation and reducing overhead. IStreamDocfile is a specific implementation of IStream with the content of the stream guaranteed to be formatted as structured storage. IStreamDocfile is implemented by message store providers.


Name Folders with Character Strings

If you access one or more folders frequently during a session, consider assigning names to the folders with the IMsgStore::SetReceiveFolder method. Although IMsgStore::SetReceiveFolder is used primarily to establish special folders to receive incoming messages for particular message classes, it can also be used to associate any folder with a name. The name can be the same as the message class or it can be any character string, customized for your client's use. Associating a name with a folder decreases the time it takes to find and open the folder.


Service Provider Basics

There are three common types of service providers:

  • Address book providers
  • Message store providers
  • Transport providers

Address book and message store providers have many similarities. They register a unique identifier with MAPI that they use for constructing entry identifiers for their objects. They provide a hierarchy of objects and properties that clients can access and manipulate. For their container objects, they support a hierarchy table and a contents table. They support event notification on these tables and optionally on individual objects so that clients can be informed of changes that occur during the session. When operations become lengthy, they can display a progress indicator to inform the user of the operation's status. Clients can communicate with address book and message store providers either indirectly through MAPI using the IAddrBook and IMAPISession interfaces or directly using one of the following service provider interfaces:

Address book provider interfaces | Message store provider interfaces
IABContainer | IMsgStore
IDistList | IMAPIFolder
IMailUser | IMessage
 | IAttach

Transport providers differ from address book and message store providers in the way they communicate with MAPI and with clients. Transport providers typically wait for MAPI to prompt them for information rather than initiate communication. Unlike the other providers, transport providers do not support a variety of objects and tables that are commonly accessed by clients. However, they do support a status object, as do all service providers, and publish its properties in the status table. Whereas address book and message store providers call IMAPISupport::SetProviderUID to register unique identifiers for constructing their entry identifiers, transport providers call IXPLogon::AddressTypes to register unique identifiers as well as address types for assuming responsibility for the delivery of particular messages.

Another type of service provider that developers can create is a messaging hook provider. Because messaging hook providers are active processes, they more closely resemble client extensions to the MAPI spooler than a type of service provider. The MAPI spooler is the only process not driven directly by client actions. Another difference between a messaging hook provider and the other types of service providers is that a messaging hook provider uses a session object instead of a support object. MAPI provides the other types of service providers with a customized support object.

Your service provider should have three header files: one public header file and two internal files. Use the public header file for configuration and for documenting properties and their values. Include in one of the internal header files all the necessary public MAPI headers; this header file should be included in all of your service provider source files. Use the other internal file to define resource identifiers.

Assign file names for your provider's executable files that are six characters or less in length. This is to allow a suffix to be appended to the end of the name to identify the platform.

Address book, message store, and transport providers perform the following tasks:

  • Supply an entry point function. For information about implementing an entry point function, see Implementing a Service Provider Entry Point Function.
  • Supply a provider and logon object to handle logon and initialization. For more information about implementing these objects, see Starting a Service Provider.
  • If the provider belongs to a message service, supply a message service entry point function. For more information about implementing message services, see Implementing a Message Service.
  • Support configuration by implementing a property sheet. For more information about property sheets, see Implementing a Property Sheet.
  • Implement a status object and support the status table. For an overview of status objects and the status table, see Status Objects and Status Table. For more information about implementing a status object, see Implementing a Status Object.
  • Handle shut down.


Using a Support Object

MAPI furnishes a support object, an object that implements the IMAPISupport : IUnknown interface, for all service providers during logon and for all message services during configuration. Support objects are not accessible by clients; they are implemented by MAPI and called only by service providers. The IMAPISupport interface is specified in the header file MAPISPI.H. Its identifier is IID_IMAPISup and its pointer type is LPMAPISUP. No MAPI properties are exposed by support objects.

A provider can be given one or more support objects, depending on the number of times MAPI logs the provider on or the number of times the provider's message service entry function is called. Typically, a provider will be logged on at least once per session. Address book and transport providers are logged on every time a client starts a session with a profile entry requesting them. Message store providers are logged on every time a client calls IMAPISession::OpenMsgStore.

In the case of multiple logons in a session, you can choose either to retain and use each support object separately or to retain and use only the first, discarding each subsequent support object. To retain a support object, call its IUnknown::AddRef method. Calling AddRef on a support object that you want to retain throughout a session is extremely important; if the call is not made, MAPI releases the support object and frees its memory.

The purpose of the support object is to provide implementations for a fairly large number of methods commonly used by the providers. Each support object also contains contextual data specific to its own instance, such as the session the provider is running in, the profile section the provider is using, and error information for the session.

There are four different types of support objects: one for each major provider type (address book, message store, and transport) and one for configuration support. Messaging hook providers run within the same thread as the MAPI spooler and are given a session object instead of a support object.

MAPI customizes each support object by including implementations of methods that are relevant for its usage. Implementations of some methods, such as OpenProfileSection, are included in all support objects. Implementations of other methods, such as SpoolerNotify, apply only to particular support objects. Only message store and transport providers can use this method; when an address book provider or a message service try to call it, MAPI returns MAPI_E_NO_SUPPORT.

Support objects can be used to accomplish many tasks, such as:

  • Accessing a profile section.
  • Copying folders or messages. See Copying or Moving a Message or a Folder.
  • Accessing objects belonging to other providers. See Supporting Object Access and Comparison.
  • Handling event notification. See Supporting Event Notification.
  • Allocating and freeing memory.
  • Obtaining a unique identifier.
  • Invalidating objects.
  • Handling errors.
  • Registering message preprocessors.
  • Preparing message delivery reports.

At logon time, MAPI calls the logon method of each service provider's provider object. For address book providers, MAPI calls IABProvider::Logon. For message store providers, MAPI calls IMSProvider::Logon. For transport providers, MAPI calls IXPProvider::TransportLogon. MAPI passes a pointer to the appropriate support object in one of the parameters to this method. The logon method in turn instantiates a logon object, passing it the support object pointer. The logon object calls the support object's IUnknown::AddRef method to retain it if necessary. For more information about the logon process for service providers, see Starting a Service Provider.

When a client logs off, MAPI calls the logon object's logoff method. The logoff method calls the support object's IUnknown::Release method to indicate that the provider no longer intends to call any of the support methods. As with logon, the logoff methods have slightly different names. The IABLogon and IMSLogon interfaces have Logoff methods; the IXPLogon interface has a TransportLogoff method.

Message service entry point functions are called when a logon attempt fails with the error MAPI_E_UNCONFIGURED or when a client initiates a configuration request. MAPI instantiates a configuration support object and calls the message service entry point function for either the unconfigured provider or the provider whose configuration is about to change. Unlike the other support objects, configuration support objects are valid only until the entry point function returns; message services do not call these objects' AddRef methods to retain them.

Typically, MAPI makes calls to a provider's message service entry point function, but sometimes a provider is asked to make the call. This can occur when a client calls a provider's IMAPIStatus::SettingsDialog method to prompt the provider to display its configuration property sheet. SettingsDialog should call IMAPISupport::GetSvcConfigSupportObj to obtain a configuration support object that it can pass to the message service entry point function.

The IMAPISupport::GetMemAllocRoutines method is available for determining the addresses of the memory allocation and deallocation functions without having to link with MAPI. Using GetMemAllocRoutines also makes it easier to trace memory leaks by surrounding the allocation function calls with debugging code. If you call GetMemAllocRoutines, as is recommended, do so before calling the CreateIProp function, which requires the allocation function addresses as parameters.

When you need to create a new address book or message store object, create and set a search key for the object in its PR_SEARCH_KEY property. Call IMAPISupport::NewUID to obtain a unique identifier to use in building a search key. Do not use your own hard-coded MAPIUID. A provider's MAPIUID should only be used for entry identifiers. For more information about constructing search keys, see Record and Search Keys.

A client application can sometimes release an object without releasing one or more of its affiliated objects. In such a case, a provider may need to render an unreleased object unusable. To do this, the provider frees all of the resources connected with the object and then calls IMAPISupport::MakeInvalid to invalidate the object's vtable. MakeInvalid replaces the vtable's IUnknown methods (QueryInterface, AddRef, and Release) with standard MAPI implementations and causes all other methods to return MAPI_E_INVALID_OBJECT. MakeInvalid also frees all the object's memory other than the vtable.


Starting a Service Provider

At some point after a client starts a session with MAPI, your service provider will be started. Transport providers are started when a client makes a request for their services. Address book and message store providers are started during the client's logon process. A client calls IMAPISession::OpenAddressBook to load each of the address book providers included in the profile and IMAPISession::OpenMsgStore to load a specific message store provider. Address book providers that are part of a message service are started before any of the other providers in the service.

MAPI starts each service provider in the active profile by:

  • Locating the name of its DLL in the profile.

    You are required to register the name of your provider DLL in the MAPISVC.INF configuration file to ensure that it appears in the profile. When your service provider is added to a profile, either individually or as part of a message service, all of the [Service Provider] sections from MAPISVC.INF that apply to your provider are copied into the profile. For more information about the structure of MAPISVC.INF, see File Format of MAPISVC.INF.

  • Calling the Windows API function LoadLibrary to load the DLL.

    Because MAPI calls LoadLibrary either every time it uses a service provider DLL, regardless of whether it has already been loaded, or only the first time, your service provider must not make assumptions about the number of times that it will be loaded. For every call to LoadLibrary, MAPI makes a call to the Windows API function FreeLibrary when a service provider DLL is no longer needed.

  • Calling the entry point function for the provider.

    MAPI calls your provider's entry point function to initiate the logon process. Entry point functions ensure that you are using a version of the service provider interface (SPI) that is compatible with the version being used by MAPI. These functions also return pointers to newly created provider objects. For information about creating an entry point function for your provider, see Implementing a Service Provider Entry Point Function.


Implementing a Service Provider Entry Point Function

Every service provider DLL has an entry point function that MAPI calls to load it. Be aware that this entry point function is not the same as DllEntryPoint, the Win32 DLL entry point function. For information about Win32 DLL entry point functions, see the Win32 Programmer's Reference.

Depending on the type of your provider, your provider entry point function conforms to a different prototype. MAPI defines four different entry point function prototypes for service providers:

Address book providers | ABProviderInit
Message store providers | MSProviderInit
Transport providers | XPProviderInit
Messaging hook providers | HPProviderInit

Much of the functionality in these prototypes is the same for all service provider types. Messaging hook providers do not implement the same functionality as the other providers. Whereas the other providers instantiate provider and logon objects, messaging hook providers instantiate spooler hook objects, or objects that implement the ISpoolerHook interface.

Address book, message store, and transport providers perform these two main tasks in their entry point functions:

  1. Check the version of the service provider interface (SPI) to make sure MAPI is using a version that is compatible with the version that your service provider is using. Use the lpulMAPIVer parameter, which contains the MAPI SPI version, and the lpulProviderVer parameter, which contains your SPI version, to perform the check.

    These parameters are 32-bit unsigned integers composed of three parts:

  • Bits 24-31 represent the major version.
  • Bits 16-23 represent the minor version.
  • Bits 0-15 represent the micro version.

    Although the major version number rarely changes, the minor version number changes whenever MAPI is released and the SPI has changed. The micro version is the Microsoft internal build version; it is used to track changes during the development process.

    MAPI defines the CURRENT_SPI_VERSION constant, documented in the MAPISPI.H header file, for indicating the present SPI version. Fail your check with the error MAPI_E_VERSION if you are using a version of the SPI that is newer than the version that MAPI is using.

  2. Instantiate a provider object. Because your provider can be started and initialized multiple times, you should instantiate a separate object each time this occurs. Providers are started multiple times when they appear in multiple profiles that are in use simultaneously by one or more clients or when they appear multiple times in a single profile.

    Just as the entry point function prototype differs depending on the type of your provider, so does the type of provider object. If you are writing an address book provider, implement IABProvider.

    If you are writing a message store provider, implement IMSProvider. See Loading Message Store Providers.

    If you are writing a transport provider, implement IXPProvider. See Initializing the Transport Provider.


Implementing Service Provider Logon

With the pointer that you return from your entry point function, MAPI calls a method in your provider object to begin the logon process. This method varies as follows, depending on the type of your service provider:

  • IABProvider::Logon for address book providers
  • IMSProvider::Logon for message store providers
  • IXPProvider:TransportLogon for transport providers
Perform the following tasks in whatever logon method you implement
  1. Increment the reference count on the support object that is passed as an input parameter by calling its IUnknown::AddRef method.
  2. Call the support object's IMAPISupport::OpenProfileSection method to access your profile section.
  3. Call the profile section's IMAPIProp::SetProps method to set the following properties:
    PR_DISPLAY_NAME PR_ENTRYID
    PR_PROVIDER_DISPLAY PR_RECORD_KEY

Note Do not attempt to set the profile section's PR_RESOURCE_FLAGS or PR_PROVIDER_DLL_NAME properties. At logon time, these properties are read-only.

  4. Check that the properties you need for configuration are either stored in the profile or are available from the user. For more information about checking your configuration, see Verifying Service Provider Configuration.
  5. Call the support object's IMAPISupport::SetProviderUID method to register a unique identifier, or MAPIUID, if your provider is an address book or message store provider. Transport providers register MAPIUIDs when MAPI calls their IXPLogon::AddressTypes method. For more information about registering a MAPIUID, see Registering Service Provider Unique Identifiers.
  6. Instantiate a logon object and return with one of the following values:
    • S_OK to indicate a successful logon.
    • MAPI_E_UNCONFIGURED to indicate that one or more of the configuration properties were unavailable.
    • MAPI_E_USER_CANCEL to indicate that the user canceled the configuration dialog box, causing configuration properties to be unavailable.
    • MAPI_E_FAILONEPROVIDER to indicate that your provider could not be configured, but that MAPI should allow it to be used regardless. Logon methods should return this value to report a non-fatal error, such as when the provider requires a password and cannot prompt the user for it because the user interface is disabled.

    For more information about logon objects, see Implementing a Logon Object.

The preceding list of tasks describes a minimum implementation for a service provider logon method. You can include additional functionality if necessary. For example, some providers call IMAPISupport::ModifyStatusRow to update the status table in their logon method.

Note To achieve the best performance at logon time, avoid calling either IMAPISupport::PrepareSubmit or IMAPISupport::SpoolerNotify. Before these calls can complete and return control to your logon method, the MAPI spooler must be started.


Verifying Service Provider Configuration

Your logon method, either IABProvider::Logon, IMSProvider::Logon, or IXPProvider::TransportLogon, must verify your provider's configuration. This involves checking that all of the properties needed for full operation are set and set correctly. Every provider requires a different number of properties; configuration depends on your provider and the degree of user interaction you allow. Some service providers keep all of the necessary properties in the profile. Other service providers keep a partial set of properties in the profile and prompt the user for missing values. Still other providers do not store properties in the profile at all, relying on the user to supply all of the information needed for configuration.

To retrieve properties stored in the profile
  1. Call IMAPISupport::OpenProfileSection, passing the MAPIUID of your provider as an input parameter.
    1. Call the profile section's IMAPIProp::GetProps or GetPropList methods to retrieve individual properties or a property list.
To set properties from user information

Display a property sheet, if MAPI has not set a flag prohibiting the display. The following flags indicate that a user interface cannot be presented.

Flag | Service provider
AB_NO_DIALOG | Address book provider
LOGON_NO_DIALOG | Transport provider
MDB_NO_DIALOG | Message store provider

If your provider does not store all of its configuration properties in the profile, requiring user interaction, and MAPI passes one of the dialog box suppression flags to your logon method, return MAPI_E_UNCONFIGURED. Also return this error when the dialog suppression flag is not set, but the user does not supply all of the required information.

When your service provider fails its logon method with MAPI_E_UNCONFIGURED, MAPI calls your entry point function again. If the information cannot be located with the second call, depending on how important your service provider is, the session might terminate.

The following illustration shows the logic required for configuration in your service provider logon method.


Implementing a Logon Object

Every address book, message store, and transport provider instantiates a logon object as part of its implementation of IABProvider::Logon, IMSProvider::Logon, or IXPProvider::TransportLogon. Logon objects implement methods that help MAPI service client requests. Depending on your type of service provider, your logon object will support the following interface.

Logon object interface | Service provider
IABLogon | Address book provider
IMSLogon | Message store provider
IXPLogon | Transport provider

Address book and message store providers implement these features in their logon objects:

  • Support for event notification (Advise and Unadvise methods). For an overview of event notification, see Event Notification in MAPI. For information about supporting notification in your logon object, see Supporting Event Notification.
  • Entry identifier comparison (CompareEntryIDs method). For general information about entry identifiers, see Entry Identifiers. For information about comparing entry identifiers in your logon object's CompareEntryIDs method, see Supporting Object Access and Comparison.
  • Access to additional error information (GetLastError method). For more information about handling errors in MAPI, see Error Handling.
  • Access to objects implemented by the service provider (OpenEntry method). For more information, see Supporting Object Access and Comparison.
  • Access to a status object (OpenStatusEntry method). For general information about status objects, see Status Objects. For specific information about implementing a status object, see Implementing a Status Object.
  • Logoff (Logoff method). For more information, see Shutting Down a Service Provider.

If your provider is an address book provider, you will also implement these methods and associated features:

  • GetOneOffTable to provide a listing of the templates that you support for creating new recipients. For more information, see One Off Tables or Implementing a Provider One Off Table.
  • OpenTemplateID to provide access to the implementation of a recipient whose data resides in a host address book provider. For more information, see Acting as a Foreign Address Book Provider.
  • PrepareRecips to insure that the appropriate properties are available for all of the recipients in a recipient list. For more information, see IABLogon::PrepareRecips.

A transport provider's logon object, which implements IXPLogon, is quite different from the logon objects implemented by the other types of service providers. It has only two features in common with the other logon objects: access to a status object through the OpenStatusEntry method and a logoff operation through the TransportLogoff method. Transport providers implement the following unique features in their logon objects:

  • Registration for address types (AddressTypes method) and message options (RegisterOptions method). For more information about registering an address type, see Creating a Minimal Transport Provider or Transport Provider-MAPI Spooler Operational Model. For more information about registering message options, see Implementing Message and Recipient Options with Transport Providers.
  • Control of message transmission (StartMessage, EndMessage and SubmitMessage methods). For more information, see Message Reception Model, Interacting with the MAPI Spooler, and Message Submission Model.
  • Internal state validation (ValidateState method).
  • Ability to download or upload messages on demand (FlushQueues method). For more information, see Implementing the FlushQueues Method.
  • Ability to query for pending messages (Poll method). For more information, see Message Reception Model.
  • Idle state detection (Idle method).
  • Interaction with the MAPI spooler (TransportNotify method).


Registering Service Provider Unique Identifiers

Address book, message store, and transport providers use a unique identifier known as a MAPIUID to register to service objects of various types. A MAPIUID is a 16-byte identifier that contains a globally unique identifier, or GUID. You can create a MAPIUID by:

  • Defining a constant.
  • Invoking the Microsoft utility UUIDGEN.EXE.

For example, an address book provider might include the following constant in a header file to define a MAPIUID:

#define AB_UID_PROVIDER  { 0Xe3, 0x3c, 0x67, 0xa0, \
                           0xc8, 0x1f, 0x11, 0xce, \
                           0xb2, 0xe4, 0x0, 0xaa, \
                            0x0, 0x51, 0xe, 0x3b  }
To register a MAPIUID if your provider is an address book or message store provider

Call IMAPISupport::SetProviderUID.

Register a MAPIUID for each logon object that you instantiate and include this MAPIUID in the first 16 bytes of the ab member of every entry identifier that you create. MAPI uses MAPIUIDs to associate objects with service providers. When a client calls the IMAPISession::OpenEntry method to open an object, MAPI examines the MAPIUID portion of the entry identifier, matching it against the registered MAPIUID, to determine which logon object should receive the open request.

If your provider is a transport, register one or more MAPIUIDs when MAPI calls your IXPLogon::AddressTypes method. MAPI uses the MAPIUIDs registered by transport providers to assign responsibility for message delivery.

Although service providers typically register a single MAPIUID, you can register multiple MAPIUIDs. If your address book or message store provider supports multiple logon objects, perhaps by permitting a user to add more than one instance of your provider to their profile, you might want to implement a different MAPIUID for each logon object. There are a few other reasons to support more than one MAPIUID:

  • You must support more than one version of your provider and the entry identifiers must represent the appropriate version. Assign a different MAPIUID for each version.
  • You want to distinguish between the types of objects you support. For example, an address book provider might want to register one MAPIUID to use in the entry identifiers of its messaging user objects and a different MAPIUID to use for distribution lists.

When there are multiple logon objects that are concurrently active, it makes sense to have unique MAPIUIDs for each one. This increases the accuracy with which MAPI matches entry identifiers to service providers and saves some work. When every logon object has its own unique identifier, MAPI can guarantee that any request it routes to a logon object can be handled by that object. When logon objects share MAPIUIDs, MAPI routes the request to the first logon object that is identified by the MAPIUID. If one of your logon objects receives a request that it cannot process because it does not handle the entry identifier, pass the request on to your next logon object before returning an error.


Shutting Down a Service Provider

When a client calls IMAPISession::Logoff to end the session and shut down all active service providers, MAPI in turn calls:

  • IABLogon::Logoff for address book providers.
  • IMSLogon::Logoff for message store providers.
  • IXPLogon::TransportLogoff for transport providers.

Each of these methods have similar implementations. The main tasks that a logoff method performs are:

  1. Releasing all open objects, including subobjects and status objects.
  2. Calling the support object's IUnknown::Release method to decrement its reference count.
  3. Removing all of your provider's registered MAPIUIDs.
  4. Removing your provider's row in the status table.
  5. Performing any tasks that relate to cleaning up resources, such as:
    • Terminating a connection with a remote server.
    • Decrementing the reference count on the logon object.
    • Removing the logon object from the list of logon objects that your provider stores.
    • In debug mode, issuing traces to locate objects that have leaked memory.

When your logoff method returns, MAPI calls:

  1. Your logon object's IUnknown::Release method.
  2. Your provider object's Shutdown method to perform any final cleanup tasks. Depending on the type of your provider, the following method is called:
    • IABProvider::Shutdown for address book providers
    • IMSProvider::Shutdown for message store providers
    • IXPProvider::Shutdown for transport providers
  3. Your provider object's IUnknown::Release method.

If your provider is a message store, a client call to IMsgStore::StoreLogoff will also initiate the shutdown process. StoreLogoff shuts down one particular message store provider and has no affect on the session. Only a message store provider can be shut down with this method; there is no explicit way for shutting down a particular address book or transport provider. For information about how to respond to a StoreLogoff call, see Shutting Down a Message Store Provider.

Your provider's DLL will be unloaded when MAPI calls the Win32 API function FreeLibrary, a call that is made after the last active client has called MAPIUninitialize. By this time, your service provider will have finished shutting down.


Shutting Down a Message Store Provider

If your provider is a message store provider, it can be shut down in two ways:

  • When a client or the MAPI spooler calls IMsgStore::StoreLogoff. Shutting down a message store provider with StoreLogoff causes the shutdown to occur in an orderly and controlled manner.
  • When a client calls IMAPISession::Logoff.

Your implementation of IMsgStore::StoreLogoff should begin by calling IMAPISupport::StoreLogoffTransports to inform MAPI that it is being shut down, indicating that any related transport providers should be logged off. When IMsgStore::StoreLogoff returns, its caller invokes your message store's IUnknown::Release method. Implement this Release method by calling the support object's IUnknown::Release method.

MAPI performs the following tasks in its implementation of IUnknown::Release for message stores:

  1. Removes all of the MAPIUIDs registered by the message store provider.
  2. Removes the message store provider's row from the status table.
  3. Calls IMSLogon::Logoff to release all open objects, subobjects, and status objects.
  4. Calls IMSLogon::Release to release the message store provider's logon object.

Some clients might omit the call to IMsgStore::StoreLogoff, initiating the shutdown of your message store provider with the call to the message store's IUnknown::Release method. A shutdown under these circumstances without the call to StoreLogoff is less orderly and controlled. Write your message store's Release method to handle this possibility and keep track of whether or not a call to IMAPISupport::StoreLogoffTransports has occurred. StoreLogoffTransports must be called once during the shutdown process. If you detect in your Release method that StoreLogoffTransports has not yet been called, invoke it with the LOGOFF_ABORT flag.


Invalidating an Object

As part of your provider's shutdown process, you might want to invalidate an object. Invalidating an object involves replacing its vtable with a vtable containing implementations for the three IUnknown methods: AddRef, Release, and QueryInterface. Invalidate an object by calling IMAPISupport::MakeInvalid, a method that is included in the support object of each of the three common provider types. Providers typically make this call in the implementation of their logon object's Logoff method.

Invalidating an object gives MAPI the ultimate responsibility for freeing the memory associated with an object. You can free all of the resources connected with an object and then call MakeInvalid to invalidate all of the methods in its inherited interfaces. Calls to any of these methods will return MAPI_E_INVALID_OBJECT. Using MakeInvalid is an option that many service providers choose to ignore.


Supporting Object Access and Comparison

Service providers can use the following two methods to open and compare objects belonging to their provider or to other providers:

IMAPISupport::OpenEntry

IMAPISupport::CompareEntryIDs

Like IMAPISession::OpenEntry for clients, providers can use their support object's OpenEntry method to access any object as long they know the object's entry identifier. Unlike the session method, the support method requires that you specify a valid entry identifier in the lpEntryID parameter. It cannot be NULL.

To illustrate how a transport provider might use IMAPISupport::OpenEntry, consider the following scenario. The transport provider has received a message formatted in Rich Text Format and does not know if the target recipient can handle this format. Before delivering the message, the transport provider needs to:

  1. Call the message's IMessage::GetRecipientTable method to access the recipient table and the recipient's entry identifier, its PR_ENTRYID property.
  2. Pass the entry identifier to IMAPISupport::OpenEntry to open the recipient, typically either a messaging user or distribution list. The lpInterface parameter should be set to NULL because the provider cannot know ahead of time the object type of the recipient.

    The support object's OpenEntry method calls IMAPISession::OpenEntry to determine the address book provider responsible for the recipient.The session object then calls the appropriate address book provider's OpenEntry method to open the recipient and return an interface pointer to the transport provider.

  3. Call the recipient's IMAPIProp::GetProps method to retrieve its PR_SEND_RICH_INFO property. If PR_SEND_RICH_INFO is set to TRUE, the recipient can handle formatted text.

If you have opened several objects from other providers, you may need to find out if two entry identifiers refer to the same object. For example, you may have a short-term entry identifier and a long-term entry identifier and these identifiers may or may not identify the same object. To avoid redundant processing, call the IMAPISupport::CompareEntryIDs method to compare these entry identifiers. You must use this method for entry identifier comparison because entry identifiers cannot be compared directly.


Supporting Event Notification

Because supporting event notification can be complicated, MAPI supplies three support object methods that implement the most difficult parts of the process. These methods work as a unit, and a provider must use all three or none of them.

The MAPI support methods use notification keys to manage the connections between the advise sinks and the objects that generate the notifications. A notification key is a NOTIFKEY structure containing binary data that identifies an object across processes. It is typically copied from the long-term entry identifier of the advise source object. If the client has supplied an entry identifier in the call to Advise, you can use it for the notification key. If the lpEntryID parameter to Advise is NULL, use the entry identifier of the outermost possible container object, such as the message store.

To use the support methods, call IMAPISupport::Subscribe whenever a client calls your Advise method to register for a notification. Allocate a NOTIFKEY structure and create a unique notification key for your advise source object. For example, a message store provider prompted to notify a client when a message is received into a particular folder creates a notification key for that folder. Pass a pointer to the NOTIFKEY structure in the call to Subscribe along with a pointer to the client's advise sink. Subscribe calls the advise sink's IUnknown::AddRef method to increment its reference count and MAPI retains the pointer until the registration is canceled.

You can pass the NOTIFY_SYNC flag to Subscribe to request that Notify behave synchronously and not return until it has made all calls to the IMAPIAdviseSink::OnNotify methods of registered advise sinks. Set this flag only for your own internal use. Do not set it when responding to a client Advise call. Event notification between clients and providers is always asynchronous. That is, MAPI guarantees that the call during which an event happens will return to the client before any of the OnNotify calls are made.

If you set the NOTIFY_SYNC flag, do not make any changes to any of the advise sink objects and do not pass a wrapper advise sink created by HrThisThreadAdviseSink to Subscribe. HrThisThreadAdviseSink creates a thread-safe version of an advise sink to be used with asynchronous notification only.

If an advise sink registered for synchronous notification returns from OnNotify with the CALLBACK_DISCONTINUE flag set, IMAPISupport::Notify sets the NOTIFY_CANCELED flag and returns without making any calls to OnNotify.

Once Subscribe has returned, you will no longer have any need to hold onto your copy of the client's advise sink. Call its IUnknown::Release method to release it. Subscribe returns a nonzero connection number that you should return to the client. The connection number represents the link between the advise source and the advise sink. It remains valid until the client makes a successful call to Unadvise.

When the client is ready to cancel a registration, it calls your Unadvise method. Pass the connection number from the Unadvise call to IMAPISupport::Unsubscribe. Unsubscribe calls the advise sink's IUnknown::Release method. As with Advise and Unadvise, calls to Subscribe and Unsubscribe must be paired. You must make one call to Unsubscribe for every call that is made to Subscribe. However, you do not have to call Subscribe every time your Advise method is called. Conversely, you can call it for setting up internal notifications.

When an event occurs, allocate one or more NOTIFICATION structures of the type appropriate for the event and call IMAPISupport::Notify. Notify generates a notification for each registered advise sink. It is recommended that all the unused members of the NOTIFICATION structure be set to zero. This technique for initializing the NOTIFICATION structure can help clients create smaller, faster, and less error-prone OnNotify implementations.

Note that a separate NOTIFICATION structure is necessary for each event, even for multiple events of the same type. For example, if three clients are registered for table notification on a particular table and five rows are added to the table, you must create five OBJECT_NOTIFICATION structures for your Notify call. A batch notification such as this results in better performance than calling Notify five times. For each Notify call, MAPI calls the IMAPIAdviseSink::OnNotify method of every registered advise sink. If there are no registered advise sinks, MAPI ignores the call.

Service providers that send batched notifications must order them so that they can be interpreted from the first notification to the last. This ordering is especially necessary when a notification batch contains a series of events such as TABLE_ROW_ADDED and one event refers to a prior row that was added in another event in the same batch.


Implementing a Message Service

A message service is one or more related service providers grouped together for the purpose of simplifying installation and configuration. MAPI recommends that all service providers be included in a message service.

To implement a message service with one or more providers
  1. Design the message service, determining the number and type of service providers to be included. For more information about how to design a message service, see Designing a Message Service.
  2. Create a setup program to install the service providers in the message service. For more information about writing a message service setup program, see Supporting Message Service Installation.
  3. Create an entry point function to perform configuration. For information about writing a message service entry point function, see Supporting Message Service Configuration and MSGSERVICEENTRY.
  4. Create a public header file containing the property tags and descriptions of valid values for any custom properties that the message service supports.


Designing a Message Service

Before you begin to write code to support your message service, it is important to create a design. Resolve the following issues in your design process:

  1. Determine how many service providers should be included in the message service. Only include related service providers, meaning providers that work with the same messaging system, in your service. Unrelated service providers do not belong in the same message service. Use the profile for integrating unrelated service providers and message services.
  2. Determine what type of service providers should be included in the message service. Most messge services include one provider of each of the common types. That is, the typical message service has one address book provider, one message store provider, and one transport provider.
  3. Determine how many DLLs should contain the message service. The number of DLLs that a message service uses depends on:
    • The degree of complexity that you as the writer of the message service are willing to handle.
    • The type of service providers in the message service.
    • The relationship that the message service might have with another message service.

    Because MAPI stores only one entry point for each provider type, do not include multiple providers of the same type in a single DLL. If it makes sense to include multiple providers of one type, either implement them in separate DLLs or have them share an entry point function.

    Another option is to implement related message services, or message services that are able to use the same installation and configuration code and the same DLL entry point function, in one DLL.

    If possible, keep it simple and use one DLL that contains the implementation of all the service providers in the message service and all the code to install and configure the message service. If this is not possible, you can implement one DLL for the installation and configuration code and either a single DLL for all of the service providers or one DLL for each provider.

  4. Determine a name for the message service DLL or DLLs. DLL names must be six characters or less so that MAPI can concatenate characters onto the end of the filename to indicate a 32-bit target platform and remain within eight characters.

    For example, if you have two DLLs, TEST and PROVS, and your message service runs on both a 16-bit platform and a 32-bit platform, MAPI generates two DLLs for each platform:

    • TEST.DLL and PROVS.DLL for the 16-bit platform.
    • TEST32.DLL and PROVS32.DLL for the 32-bit platform.


Supporting Message Service Installation

The setup program for installing your message service should:

  1. Copy message service files, such as the message service and service provider DLLs, from a CD or disk to a local drive on the workstation. The files that need to be copied depend on your message service. Typically you will copy at least one DLL.
  2. Add entries to the MAPISVC.INF configuration file. For information about how to modify this file to support the service providers in your message service, see File Format of MAPISVC.INF.
  3. Add entries as appropriate to the WIN.INI initialization file for 16-bit message services or the system registry for 32-bit message services. For details about the entries that should appear in the WIN.INI file or the system registry, see Installing MAPI.
  4. Create a default profile if one does not yet exist using one of the following:
    • NEWPROF utility to create a profile programmatically from information contained in a .PRF file. For more information, see Creating a Profile with NEWPROF.
    • Profile Wizard to create a profile with user interaction through a series of dialog boxes. For more information about using the Profile Wizard, see Creating a Profile with the Profile Wizard.
    • Control Panel to create a profile with user interaction. The Control Panel offers the user more flexibility than the Profile Wizard in configuring the message services and setting profile properties.

Place the setup program in a designated public directory. This is important because most configuration clients, such as the Control Panel, require that users enter the name of the directory. The Control Panel invokes a setup program when a user clicks the Add button, invokes the Have Disk dialog box, and specifies the path to the program. The Control Panel runs the program and calls your message service's entry point function with the ulContext parameter set to MSG_SERVICE_INSTALL.

Warning Because profiles are an expendable part of the MAPI architecture, make sure that your installation program does not store anything in the default profile that would be difficult to recreate. There are no utilities for profile recovery, for moving profiles from one machine to another, for off-line backup, or for individual or global restoration from backup copies.


Supporting Message Service Configuration

To support message service configuration
  1. Implement an entry point function that conforms to the MSGSERVICEENTRY prototype. Message service entry point functions manage access to configuration data and are called:
    • When a client logs on to retrieve information for configuring your message service.
    • When a client wants to view or change a configuration property.

    Although most message services will provide entry point functions and MAPI strongly recommends that they do, these functions are not strictly required. Message services can provide access to configuration data in other ways. However, using an entry point function standardizes and simplifies the process of configuration.

    MAPI expects all message service entry point functions to be able to store and retrieve properties from the profile sections that are associated with their message service. You can support this functionality interactively, programmatically, or both interactively and programmatically.

    To support interactive configuration, provide a property sheet that displays the properties involved in configuring your message service. As an option, you can also supply property sheets for each configurable provider. Some message services restrict users to a read-only view of configuration properties; other message services allow them to make changes.

    To support programmatic configuration, your message service entry point function must be able to work without user intervention. If your message service can be called by the Profile Wizard, you must support programmatic configuration. If your message service does not allow itself to be configured with the Profile Wizard, you can choose whether or not to support programmatic configuration.

    For more information about how to support configuration in a message service entry point function, see MSGSERVICEENTRY.

  2. Publish the name of your message service entry point function in the MAPISVC.INF configuration file by including the following entry in the message service section:
PR_SERVICE_ENTRY_NAME=<name of message service>
  3. Create one or more property sheet dialog boxes for displaying configuration data.
  4. Perform the following tasks if you want to allow the Profile Wizard to configure your message service:
    • Implement an entry point function that conforms to the WIZARDENTRY prototype.
    • Implement a standard Windows dialog procedure that conforms to the SERVICEWIZARDDLGPROC prototype.
    • Enhance your message service entry point function to respond to additional events.


Implementing a Property Sheet

A property sheet is a dialog box for displaying the properties of an object. The properties can be read-only, enabling the user only to view them, or read/write, enabling the user to make changes. A property sheet contains one or more overlapping child windows called pages, each page contains control windows for setting a group of related properties. Users navigate from page to page by selecting a tab that brings the corresponding page to the foreground of the property sheet.

Service providers are required to implement a property sheet that displays a minimal set of properties related to configuration in the message service. If you allow these message service properties to be changed, you can either allow users of client applications such as the Control Panel applet to make the changes or implement the changes programmatically. Implementing property sheets to display and edit other types of properties is optional.

Typically, you will need to display a property sheet:

  • When a client calls your status object's IMAPIStatus::SettingsDialog method.
  • When MAPI calls your provider object's logon method.
  • When MAPI calls the entry point function for your provider's message service.

Transport providers also implement property sheets to display properties related to message options, and address book providers implement property sheets to view and edit detailed information about messaging users and distribution lists, advanced search criteria, and templates for entering new users.

There are three techniques for creating a property sheet:

  • Manually, as you would any dialog box.
  • Using the property sheet common control provided in the Platform SDK.
  • Using a MAPI display table.

MAPI recommends that providers choose the third option; create a property sheet using a display table. This is the simplest option because it eliminates the need to work with the Windows user interface.

To implement a property sheet built from a display table for your message service properties
  1. Call IMAPISupport::OpenProfileSection to open a section in the current profile. Pass your MAPIUID or NULL to open your provider's profile section.
  2. Call CreateIProp to create a property data object.
  3. Call the profile section's IMAPIProp::CopyTo method to copy all of the section's properties to the property data object.
  4. Create a display table either by building one or more DTPAGE structures that describe the controls to appear on the property sheet and calling the BuildDisplayTable function or by implementing custom code.
  5. Call IMAPISupport::DoConfigPropSheet to display a property sheet with the copied properties. Pass a pointer to the property data object as the lpConfigData parameter and a pointer to the display table as the lpDisplayTable parameter. If you want to override the default access mode for this property sheet, do not set the DT_EDITABLE flag for each control in the display table that represents a read-only property.
  6. When all of the changes have been made in the property sheet, call the property data object's IMAPIProp::CopyTo method to copy the changed properties back to the profile section.

For an overview of display tables, see Display Tables.

For detailed information about display tables, see Implementing a Display Table.

For information about implementing a control, see Implementing a Control Object.

To retrieve the index of a control selected by a user in a display table list box, wait until the user clicks OK or Apply Now. At this point, the entry identifier of the selected item is written back to the IMAPIProp interface as the value of the property specified by the ulPRSetProperty member in the DTBLLBX structure.

If you need to be able to add or remove items from your list box, using a display table and IMAPISupport::DoConfigPropsheet will not work. Instead, consider implementing a property sheet with the Win32 property sheet API contained in COMDLG32.DLL.


Implementing a Display Table

A display table is used to show a property sheet — a special dialog box that is made up of one or more tabbed property pages dedicated to displaying and possibly editing one or more properties. Associated with every display table is an IMAPIProp interface implementation. The IMAPIProp implementation maintains the property data that is presented in the property sheet.

The following illustration is an example of a property sheet that displays the properties of a messaging user:

The rows in a display table represent the controls in the property sheet. Most controls can be associated with properties maintained with the IMAPIProp implementation. When a user changes the value of a modifiable control, the corresponding property is updated.

The columns in a display table represent properties of the control, such as its position in the property sheet, its type, associated structure, and identifier. For a complete list of required display table columns, see Display Tables.

MAPI displays a property sheet to the user of a client application by reading property values from the IMAPIProp implementation associated with the display table or from the display table directly. As the user works with the property sheet, changing values in the controls, MAPI calls IMAPIProp::SetProps to save a changed control if the control's DT_SET_IMMEDIATE flag is set. For controls without the DT_SET_IMMEDIATE flag set, changes to properties are saved when the user dismisses the dialog box by clicking the OK or Apply Now button. When either of these buttons or the Cancel button is clicked, MAPI removes the property sheet from view.

MAPI gains access to your display table either by calling the OpenProperty method in the IMAPIProp implementation and requesting the PR_DETAILS_TABLE property or by inheriting it in a call that you have made to MAPI, such as IMAPISupport::DoConfigPropsheet.

The first access technique is used when address book providers are asked to show details about messaging users or distribution lists. The following processing occurs:

  1. A client calls the IAddrBook::Details method.
  2. MAPI calls the address book provider's IABLogon::OpenEntry method to access the messaging user that represents the selected entry.
  3. MAPI calls the messaging user's IMAPIProp::OpenProperty method to retrieve the PR_DETAILS_TABLE property, the display table for the details dialog box.
  4. MAPI displays the dialog box, handling the user's interaction with the information, and removes it when the user has finished.

A combination of the two access techniques is used when transport providers are asked to show a message options property sheet. The transport provider makes the property interface available to MAPI through a callback function. MAPI then calls the property interface to open the PR_DETAILS_TABLE property.

Before a message options property sheet can be shown, the transport provider must:

  1. Make the message options properties available by returning an OPTIONDATA structure with information about supported options when MAPI calls its IXPLogon::RegisterOptions method.
  2. Implement a function that conforms to the OPTIONCALLBACK prototype. The OPTIONCALLBACK function handles the data stored in the OPTIONDATA structure.

When it is time to show the message options property sheet, the following processing occurs:

  1. The client calls IMAPISession::MessageOptions.
  2. MAPI calls the transport provider's OPTIONCALLBACK function which returns an IMAPIProp interface implementation. The OpenProperty method of this implementation supports the PR_DETAILS_TABLE property.
  3. When the OPTIONCALLBACK function returns, MAPI calls OpenProperty to open PR_DETAILS_TABLE and retrieve the display table describing the message options dialog box.
  4. MAPI displays the dialog box, handling the user's interaction with the information, and removes it when the user has finished.


BuildDisplayTable and Related Structures

Creating a display table is similar to writing a program with a scripting language. You can create a display table either by calling BuildDisplayTable or writing custom code to populate the rows and columns of the table. MAPI recommends the BuildDisplayTable technique because it is simpler.

Before you can call BuildDisplayTable to prompt MAPI to create a display table, there is a hierarchy of structures that you must build. The top level structure, the DTPAGE structure, describes a single tabbed property page. Within every DTPAGE structure is a DTCTL structure describing a single control, such as an edit box or a radio button. Each DTCTL structure contains a structure that is specific to the type of control. For example, if the DTCTL structure is describing an edit box control, it will contain a DTBLEDIT structure. The DTCTL structure for a radio button contains a DTBLRADIOBUTTON structure.

These structures relate directly to BuildDisplayTable; they have no meaning outside the context of this function. When you call BuildDisplayTable, you pass one or more DTPAGE structures as input parameters. The DTPAGE structures contain an array of DTCTL structures and a count of the number of DTCTL structures in the array. There is one structure for every control to appear in the dialog box. DTPAGE structures also have a character string that represents the name of a corresponding help file and dialog resource.

Each DTCTL structure in a DTPAGE structure contains data that is used to set properties for the control:

  • Control type for setting PR_CONTROL_TYPE
  • Control flags for setting PR_CONTROL_FLAGS
  • Notification data for setting PR_CONTROL_ID
  • Control structure for setting PR_CONTROL_STRUCTURE

DTCTL structures also contain a resource identifier and, for edit and combo box controls, a character filter.

The control structure member of a DTCTL structure describes the data that is unique for the type of control. MAPI defines a different structure for each control type. For example, the data of an edit control is represented by a DTBLEDIT structure; the data of a list box by a DTBLLBX structure.

The relationship between these three types of display table structures is illustrated in the following diagram. The dialog box described by this display table has two controls: a label and an edit control. The DTBLLBX structure has a label offset member, as do several of the control structures, that describes where the character string for the label begins. Label character strings are typically placed in memory immediately following the structure.


Display Table Controls

There are many different types of controls, none unique to MAPI. However, MAPI defines its own structures that are used in conjunction with BuildDisplayTable to describe the unique set of data involved with each control.

The following table describes the structures that describe each type of control.

Control structure | Description
DTBLBUTTON | Describes a button control.
DTBLCHECKBOX | Describes a check box control.
DTBLCOMBOBOX | Describes a combo box control.
DTBLDDLBX | Describes a drop down list box control.
DTBLEDIT | Describes an edit control.
DTBLGROUPBOX | Describes a group box control.
DTBLLABEL | Describes a label control.
DTBLLBX | Describes a list box control.
DTBLMVDDLBOX | Describes a multi-value drop down list box control.
DTBLMVLISTBOX | Describes a multi-value list box control.
DTBLPAGE | Describes a tabbed page control.
DTBLRADIOBUTTON | Describes a radio button control.


Display Table Rows and Columns

To illustrate how the rows and columns of a display table map to fields on a page in a property sheet, consider the following example. This property page is typical of the type that an address book provider might display to allow users to define new Internet recipients. There are only four controls: two labels and two edit controls.

The corresponding display table contains four rows, one for each control. The values for the columns that indicate position would be as follows.

Control | XPOS | YPOS | DELTAX | DELTAY
Display name label | 14 | 18 | 49 | 8
Display name edit box | 76 | 16 | 89 | 12
E-mail address label | 14 | 42 | 50 | 8
E-mail address edit box | 76 | 40 | 89 | 12
Check box | 14 | 64 | 90 | 12

This next table suggests appropriate values for the control's type, its PR_CONTROL_TYPE property, and bitmask of flags, its PR_CONTROL_FLAGS property.

Control | Type | Flags
Display name label | DTCT_LABEL | 0
Display name edit box | DTCT_EDIT | DT_EDITABLE | DT_REQUIRED
E-mail address label | DTCT_LABEL | 0
E-mail address edit box | DTCT_EDIT | DT_EDITABLE | DT_REQUIRED
Check box | DTCT_CHECKBOX | DT_EDITABLE

The final table lists each control with the contents of its associated control structure. Notice that the value for each of the label controls appears in memory directly following the structure.

Control | Structure
Display name label | {sizeof(DTBLLABEL), 0} "Display name:"
Display name edit box | {sizeof(DTBLEDIT), 0, 80, PR_DISPLAY_NAME}
E-mail address label | {sizeof(DTBLLABEL), 0} "E-mail address:"
E-mail address edit box | {sizeof(DTBLEDIT), 0, 80, PR_EMAIL_ADDRESS}
Check box | PR_SEND_RICH_INFO

Note The OK, Cancel, and Help buttons are not included in the display table. The user interface can add context to a dialog box by adding controls not in the display table.


Implementing a Control Object

Control objects, or objects that support the IMAPIControl interface, are implemented by providers to add functionality to a button that appears on a MAPI dialog box. Control objects can only be implemented for buttons.

IMAPIControl has three methods: GetLastError, GetState, and Activate.

MAPI calls IMAPIControl::GetState to determine whether or not to disable the button. GetState is called:

  • When the dialog box on which the button appears is first displayed.
  • When a display table notification is issued for the button.

Set the contents of the lpulState parameter to MAPI_DISABLED if the user cannot interact with the button and MAPI_ENABLED if the user can interact.

When the user clicks the button, MAPI calls Activate. Activate performs the task that has been associated with the button. This task can be anything appropriate for your provider, such as displaying a dialog box or updating a property. If the task is unsuccessful because the user has canceled it, return MAPI_E_USER_CANCEL. With other causes of failure, return the appropriate error value.

If the task is successful and it is linked to a property change that is reflected in another control on the dialog box, call ITableData::HrNotify. HrNotify is called to issue a display table notification with the changed property's PR_CONTROL_ID in the TABLE_NOTIFICATION structure. Do not place the new property value in the structure; return it instead when IMAPIProp::GetProps is called. Although typically a display table notification cannot be used to disable or enable a control, it can be used with a button. MAPI will refresh the changed control to respond to the notification.

MAPI calls the control's GetLastError method when Activate returns an error other than MAPI_E_USER_CANCEL. If GetLastError places extended error information in the MAPIERROR structure that it returns in the contents of the lppMAPIError parameter, MAPI displays it for the user.


Implementing a Status Object

All service providers are required to implement a status object and furnish properties from it to the session status table. You can include one or more rows in the status table, depending on the number of resources that you control. A transport provider, for instance, should create a row in the status table for each message queue it manages. When changes occur, the appropriate status table row must be updated. Status objects are implemented to provide access both to the information included in the status table and to additional information not included in the table.

To implement a status object
  1. Implement the OpenStatusEntry method of your logon object. When clients want to open your status object, they call IMAPISession::OpenEntry. MAPI fulfills the open request by calling your provider's OpenStatusEntry method, causing your provider to open its status object and return to the client a pointer to its IMAPIStatus implementation.

    In your OpenStatusEntry implementation:

    1. Perform the following tasks if your logon object has not yet created a status object:
      1. Call the support object's IMAPISupport::OpenProfileSection method to access your provider's profile section.
      2. Create a new status object.
      3. Store a reference to the profile section in your provider's status object and call the profile section's IUnknown::AddRef method to increment its reference count.
      4. Store a reference to the logon object in your provider's status object and call the logon object's IUnknown::AddRef method to increment its reference count.
      5. Store a reference to the status object in your provider's logon object.

    2. Call the status object's IUnknown::AddRef method to increment its reference count in the logon object.
    3. Set the status object's PR_OBJECT_TYPE property to MAPI_STATUS.
    4. Set the lppMAPIStatus output parameter to point to the status object and return.
    5. Check the ulFlags input parameter. If it is set to MAPI_MODIFY and your provider supports read/write access to its status object, return a writeable object. However, if your provider does not support read/write access to its status object, do not fail. Return a status object that is read-only. Clients expecting to receive read/write status objects should verify that read/write access has been granted before attempting to make any changes.

  2. Set all of the required status object and status table properties. The properties that you include in your status table row should be available through your status object, except for the properties calculated by MAPI. The required properties are:

    PR_DISPLAY_NAME

    PR_PROVIDER_DLL_NAME

    PR_PROVIDER_DISPLAY

    PR_RESOURCE_TYPE

    PR_RESOURCE_METHODS

    PR_RESOURCE_FLAGS

    PR_STATUS_CODE

  3. Implement the IMAPIStatus methods that are appropriate for your provider. Depending on your provider, you do not need to implement all of the four methods in IMAPIStatus. Every provider should implement a read-only version of the methods of the IMAPIProp interface and the IMAPIStatus::ValidateState method. Transport providers are strongly recommended to also implement FlushQueues and all providers are encouraged to support SettingsDialog. However, support for ChangePassword is optional. Only service providers that require passwords and want to allow users to change them programmatically need to implement this method.

    For every method that you support, set the corresponding bit in the PR_RESOURCE_METHODS property. For example, if you support ValidateState and SettingsDialog only, set PR_RESOURCE_METHODS to:

STATUS_VALIDATE_STATE | STATUS_SETTINGS_DIALOG

Clients should check the value of PR_RESOURCE_METHODS before attempting to call your status object. Handle calls to any of your unsupported methods by returning MAPI_E_NO_SUPPORT.

  1. Call IMAPISupport::ModifyStatusRow during logon to add your row or rows to the status table. Pass a property value array containing the column information for the row and zero for the ulFlags parameter. If at some point later in the session your provider's status changes and it becomes necessary to update the column information, call ModifyStatusRow again with the STATUSROW_UPDATE flag set.

For an overview of status objects, see Status Objects.


Displaying a Progress Indicator

Many of the operations that you perform for clients can take a long time to complete. To inform clients of the progress of a lengthy operation, you can show an indicator that displays graphically the finished portion of an operation at any given point from the start of the operation to its completion. Typically, the progress indicator looks something like the following illustration, with each tic mark representing a percentage of the total operation to be completed.

The following methods support lengthy operations and the display of a progress indicator:

  • The CopyMessages, CopyFolder, DeleteMessages, DeleteFolder, EmptyFolder, and SetReadFlags methods in IMAPIFolder
  • The CopyProps and CopyTo methods in IMAPIProp
  • The DoCopyProps, DoCopyTo, CopyFolder, and CopyMessages methods in IMAPISupport
  • IMessage::DeleteAttach
  • IABContainer::CopyEntries

To display a progress indicator, MAPI defines a progress object. Progress objects implement the IMAPIProgress interface, an interface which includes methods for establishing the range of the indicator and creating the display. MAPI provides a progress object implementation as do some clients. You should use a client's implementation if one is supplied as an input parameter to the method performing the operation. If the client passes NULL instead of a pointer to a progress object, use MAPI's implementation by calling IMAPISupport::DoProgressDialog.


Using Progress Objects

With the methods and data of a progress object, you can control how the indicator reports progress. Although a client or MAPI implements the progress object, most of the burden of insuring the correctness of the progress display falls on service providers. You can guarantee its accuracy by specifying a particular order and value for the parameters that are passed to progress object methods.

The following parameters are passed to progress objects:

  • A bitmask of flags, set with SetLimits and retrieved with GetFlags.
  • A minimum value (local and global), set with SetLimits and retrieved with GetMin.
  • A maximum value (local and global), set with SetLimits and retrieved with GetMax.
  • A value that indicates the current percentage of completion of the operation, passed to Progress.
  • A count of the number of objects that have so far been processed, passed to Progress.
  • A count of the total number of objects involved in the operation, passed to Progress.

All service providers begin their progress display processing with a call to IMAPIProgress::GetFlags to retrieve the present flags setting. Currently, the flags can be set only to MAPI_TOP_LEVEL. Clients and MAPI initialize the flag to MAPI_TOP_LEVEL, relying on service providers to clear it when appropriate.

The flags value is set to MAPI_TOP_LEVEL while you are working with the top-level object in the operation. The top-level object is the object that is called by the client to begin an operation. In a folder copy operation, this is the folder being copied. In a folder delete operation, this is the folder being deleted. When you make a call to process a lower level object, or subobject, clear the flags value. In a folder copy operation, subobjects are the subfolders that are in the folder being copied.

MAPI allows you to differentiate between top-level objects and subobjects with the MAPI_TOP_LEVEL flag so that all objects involved in an operation can use the same IMAPIProgress implementation to show progress, thereby causing the indicator display to proceed smoothly in a single positive direction. Whether or not the MAPI_TOP_LEVEL flag is set affects the settings of the other parameters in subsequent calls to the progress object.

Because it can be nontrivial to set appropriate parameter values for a progress display at all levels of a multi-level operation, some service providers elect not to show progress for subobjects.

To avoid showing progress for subobjects
  • Pass NULL for the lpProgress parameter in the call to process a subobject. For example, if copying folders, this is the call to a subfolder's IMAPIFolder::CopyFolder method.
  • Write special code to determine how to interpret the lpProgress parameter. Because a NULL value for the lpProgress parameter can also mean that the client should display progress using the MAPI implementation, special code is necessary to determine when to ignore the lpProgress parameter and when to call IMAPISupport::DoProgressDialog.

Call IMAPIProgress::SetLimits to set or clear the MAPI_TOP_LEVEL flag and to set local and global minimum and maximum values. The value of the flags setting affects whether the progress object understands the minimum and maximum values to be local or global. When the MAPI_TOP_LEVEL flag is set, these values are considered global and are used to calculate progress for the entire operation. Progress objects initialize the global minimum value to 0 and the global maximum value to 1000.

When MAPI_TOP_LEVEL is not set, the minimum and maximum values are considered local and are used internally by providers to display progress for lower level subobjects. Progress objects save the local minimum and maximum values only so that they can be returned to providers when GetMin and GetMax are called.

The value, object count, and object total parameters are input to the IMAPIProgress::Progress method. The value parameter, a number that indicates the percentage of progress, is required. If the MAPI_TOP_LEVEL flag is set, you can also pass an object count and an object total. Some clients use these values to display a phrase such as "5 items completed out of 10" with the progress indicator. Progress on an operation can be reported strictly as a percentage or as a percentage and in terms of the number of items that have been processed out of the total to be processed. For example, if you are a message store provider and you are performing a copy operation that is copying 10 folders, the progress indicator can supply the user with additional information by displaying a phrase such as 1 of 10, 2 of 10, 3 of 10, and so on until the operation is complete.


Displaying Progress Step by Step

To display a progress indicator, call IMAPIProgress::GetFlags to retrieve the current flags setting.

If the MAPI_TOP_LEVEL flag is set
  1. Set a variable equal to the total number of items to process in the operation. For example, if you are copying the contents of a folder, this value will be equal to the number of the subfolders in the folder plus the number of messages.
  2. Set a variable equal to 1000 divided by the number of items.
  3. If you are showing progress for subobjects, call the progress object's IMAPIProgress::SetLimits method and pass the following values for the three parameters:
    • Set the lpulMin parameter to 0.
    • Set the lpulMax parameter to 1000.
    • Set the lpulFlags parameter to MAPI_TOP_LEVEL.
  4. For each object to be processed:
    1. Call IMAPIProgress::SetLimits and pass the following values for the three parameters:
· Set the lpulMin parameter to the variable set in step 2 multiplied by the current item minus 1.
· Set the lpulMax parameter to the variable set in step 2 multiplied by the current object.
· Set the lpulFlags parameter to 0.

  2. Perform whatever processing should be done on this object. If this is a subobject and you want to display progress on subobjects, pass a pointer to the progress object in the lpProgress parameter to the method.
  3. Call IMAPIProgress::Progress and pass the following values for the three parameters:
· Set the ulValue parameter to the variable set in step 2 multiplied by the current object.
· Set the ulCount parameter to the current object.
· Set the ulTotal parameter to the variable set in step 1, the total number of objects.

If the MAPI_TOP_LEVEL flag is not set
  1. Call the progress object's IMAPIProgress::GetMin method to retrieve the minimum value for the display.
  2. Call IMAPIProgress::GetMax to retrieve the maximum value for the display.
  3. Set a variable equal to the total number of objects to be processed.
  4. Set a variable equal to the result of subtracting the minimum value from the maximum value and then dividing by the total number of objects.
  5. For each object to be processed:
    1. If your provider is showing progress for subobjects, call IMAPIProgress::SetLimits and pass the following values for the three parameters:
· Set the lpulMin parameter to the minimum value plus the current item minus 1 multiplied by the variable set in step 4.
· Set the lpulMax parameter to the minimum value plus the current unit multiplied by the variable set in step 4.
· Set the lpulFlags parameter to 0.

  2. Perform whatever processing should be done on this object. If the object is a subobject, and your provider displays progress for subobjects, pass a pointer to the progress object in the lpProgress parameter to the method.
  3. Call IMAPIProgress::Progress and pass the following values for the three parameters:
· Set the ulValue parameter to variable set in step 2 multiplied by the current object.
· Set the ulCount parameter to 0.
· Set the ulTotal parameter to 0.

The following code sample illustrates the logic required to show progress at all levels of an operation that copies the contents of a folder containing five subfolders.

lpProgress->GetFlags (lpulFlags);
ulFlags = *lpulFlags;

/* Folder in charge of the display. It contains 5 subfolders. */
if (ulFlags & MAPI_TOP_LEVEL)
{
    ulItems = 5                         // 5 subfolders in this folder
    ulScale = (ulMax / ulItems)         // 200 because ulMax = 1000
    lpProgress->SetLimits(0, ulMax, MAPI_TOP_LEVEL)

    for (i = 1; i <= ulItems; i++)      // for each subfolder to copy
    {
        lpProgress->SetLimits( (i - 1) * ulScale, i * ulScale, 0)
        CopyOneFolder(lpFolder(i), lpProgress)
        lpProgress->Progress( i * ulScale, i, ulItems)
    }
}
else
/* One of the subfolders to be copied. It contains 3 messages */
{
    lpProgress->GetMin(&ulMin);
    lpProgress->GetMax(&ulMax);
    ulItems = 3;
    ulDelta = (ulMax - ulMin) / ulItems;
    for (i = 1; i <= ulItems; i++)
    {
        lpProgress->SetLimits(ulMin + (i - 1) * ulDelta,
                              ulMin + i * ulDelta, 0)
        CopyOneFolder(lpFolder(i), lpProgress)

        /* Pass 0 for ulCount and ulTotal because this is not the */
        /* top level display and that information is unavailable  */
        lpProgress->Progress( i * ulDelta, 0, 0)
    }
}


Developing an Address Book Provider

An address book provider supplies recipient information to client applications, to message store and transport providers, and to MAPI. Recipient information is organized hierarchically into storage compartments known as containers. Every address book in the profile contributes one or more top-level, or parent, containers to the MAPI address book, an integrated view of recipient information from all address book providers in a session. It is through the MAPI address book that clients and other service providers gain access to the data of an address book provider.

MAPI builds the integrated address book by:

  1. Retrieving the top-level containers from each address book provider.
  2. Retrieving each container's hierarchy table.
  3. Copying each hierarchy table into an integrated hierarchy table. It is the integrated hierarchy table that is exposed to the client.

MAPI imposes few requirements on address book provider writers. The range of possible features you can implement as an address book writer is varied and flexible. For example, your provider could be limited to supplying a read-only view of a particular type of recipient information or implement a full set of features, perhaps allowing clients or providers to make additions or modifications to the recipient data and to impose search criteria for defining customized views.

Your provider's data can reside locally in a file or database or on a remote server. Some address book providers are meant to work with a particular messaging system, tightly coupled with a transport provider, while others can operate with any messaging system.

MAPI defines a special type of address book provider called a personal address book, or PAB, that implements a single modifiable container and can hold recipient information copied from other containers as well as information created directly. Although any address book provider can implement a PAB and multiple PABs can be added to a profile, only one of these providers can be designated to operate as the PAB during any one session.


Required Features for Address Book Providers

Address book providers can work with recipient information that is temporary or permanent, local or remote, understandable by one or more messaging systems, and formatted for a disk file or database table. There are a variety of features that an address book provider can implement, thereby adding value and improving interoperability with clients and other providers. However, a few features are required.

The following table describes features that are required of all address book providers and the steps that you need to take to implement them.

Feature | How to implement
Session logon | 1. Implement an entry point function. See Implementing an Address Book Provider Entry Point Function. 2. Implement the IABProvider::Logon method. See Implementing Address Book Provider Logon and Logoff.
Session logoff | Implement the IABProvider::Shutdown method. See Implementing Address Book Provider Logon and Logoff.
Create entry identifiers | Provide support for the PR_ENTRYID property. See Entry Identifiers and Address Book Identifiers.
Contribute to the status table | 1. Implement the appropriate methods of the IMAPIStatus interface. See Implementing a Status Object. 2. Support the required status table properties. See Status Table. 3. Call IMAPISupport::ModifyStatusRow.
Provide limited status object support | 1. Implement the IMAPIStatus::ValidateState method. 2. Return MAPI_E_NO_SUPPORT from the other IMAPIStatus methods.
Support interactive and programmatic configuration | 1. Implement a message service entry point function. 2. Implement a display table. See Display Tables and Implementing a Display Table. 3. Implement a property sheet or call the IMAPISupport::DoConfigPropsheet method. See Implementing a Property Sheet.

In addition, if your provider supports recipient creation, you must supply a list of creation templates. Supply this list by implementing the IABLogon::GetOneOffTable method to include all of the templates supported by your provider and the IMAPIProp::OpenProperty method of each container to open the PR_CREATE_TEMPLATES property and include all the templates supported by the container. For more information, see Implementing One-Off Tables.


Implementing an Address Book Provider Entry Point Function

When a client application calls MAPILogonEx to begin a session using a profile that contains your address book provider, MAPI loads your provider and all others that are part of the profile. MAPI learns of the name of your provider's entry point function by looking in the profile. Remember that this function is not the same as a DLL entry point function; see the documentation for DllEntryPoint in the Win32 documentation.

There are several entries, some of which must appear in the MAPISVC.INF configuration file, that are included in the profile section of every address book provider. The following table lists these profile section entries and whether or not the MAPISVC.INF file must include them.

Profile section entry | MAPISVC.INF requirement
PR_DISPLAY_NAME=string | Optional
PR_PROVIDER_DISPLAY=string | Required
PR_PROVIDER_DLL_NAME=DLL filename | Required
PR_RESOURCE_TYPE=long | Required
PR_RESOURCE_FLAGS=bitmask | Optional

Your address book provider can place this information into a profile directly by calling its profile section's IMAPIProp::SetProps method or indirectly by modifying MAPISVC.INF. Profiles are built using the relevant information in MAPISVC.INF for the selected service providers or message services. For more information about the organization and contents of MAPISVC.INF, see File Format of MAPISVC.INF.

The name of your address book provider's DLL entry point function must be ABProviderInit and it must conform to the ABProviderInit prototype. Perform the following tasks in your provider's DLL entry point function:

  • Check the version of the service provider interface (SPI) to make sure MAPI is using a version that is compatible with the version that your address book provider is using.
  • Instantiate an address book provider object.

Do not call either MAPIInitialize or MAPIUninitialize in this function.

The DLL entry point function instantiates a provider object and returns to MAPI a pointer to that object.


Implementing Address Book Provider Logon and Logoff

Address book providers support session logon and logoff by implementing the methods of the IABProvider interface. The IABProvider interface inherits directly from IUnknown and adds only two other methods: Logon and Shutdown.

MAPI will call your provider's IABProvider::Logon method at the beginning of every session and whenever your provider is added to the current profile and the client supports dynamic reconfiguration. When MAPI calls the IABProvider::Logon method, your address book provider begins its logon process.

To implement IABProvider::Logon
  1. Initialize all of the output parameter pointers passed in by MAPI.
  2. Call the support object's IUnknown::AddRef method to increment its reference count.
  3. Call the support object's IMAPISupport::OpenProfileSection method to open the section of the profile that contains configuration information about your provider. Pass NULL for the lpUID parameter and the MAPI_MODIFY flag if you intend to make changes.
  4. Call the profile section's IMAPIProp::GetProps method to retrieve the properties that your provider needs for logon, such as the name of the data file or database table.
  5. Check that the properties are all available and valid. If necessary and allowed, display a dialog box to prompt the user to make corrections or additions to invalid or missing information and call the profile section's IMAPIProp::SetProps method to save any changes. Some of the common properties that should be available include:

    PR_DISPLAY_NAME

    PR_ENTRYID

    PR_PROVIDER_DISPLAY

    PR_RECORD_KEY

Note Do not set PR_RESOURCE_FLAGS or PR_PROVIDER_DLL_NAME. At logon time, these properties are read-only.

  6. If one or more configuration properties are unavailable, fail and return the value MAPI_E_UNCONFIGURED.
  7. Call IMAPISupport::SetProviderUID to register a MAPIUID. Your provider can create a MAPIUID by:
    • Calling the IMAPISupport::NewUID method.
    • Calling the UUIDGEN.EXE tool to define a GUID that your provider uses to include in one of its header files.
  8. If desired, save a newly created MAPIUID in the current profile by calling the profile section's IMAPIProp::SetProps method.
  9. Release the profile section by calling its IUnknown::Release method.
  10. Instantiate a new logon object and set the contents of the lppABLogon parameter to the address of this new object.

Because it is possible for MAPI to call your Logon method several times during a session, it is wise to support this possibility in your implementation by being able to create multiple logon objects and keep track of each object that is created. Supporting multiple Logon calls enables a user of a client application, for example, to log on to a session with different identities or use different delivery destinations.

Shutdown is called when the session is ending. MAPI calls your IABProvider::Shutdown method as one of the last tasks involved in shutting down a session. MAPI has released all of your provider's logon objects and, when your provider receives this call, it can assume that this is the last call it will receive. In your implementation of IABProvider::Shutdown, perform any final cleanup that you feel is necessary. For example, your provider might call MAPIDeinitIdle if it has called MAPIInitIdle to use the idle engine during the session or the IUnknown::Release method of any objects that have yet to be released.

If your provider has no final cleanup, its implementation can be made up of a single line of code:

return ResultFromScode(S_OK);


Required Features for Address Book Containers

Most address book providers support at least one container, some of them modifiable. Address book containers can supply contents and hierarchy tables, search capabilities, and name resolution. Modifiable containers allow the deletion of entries such as messaging users, distribution lists, or other containers and the addition of entries from entries in other containers or from one-off templates.

The following table describes features that are required of address book providers that have containers, modifiable or read-only, and how you implement them.

Feature | How to implement
Access messaging users | Implement the IABLogon::OpenEntry method. See Opening Address Book Entries.
Compare messaging users | Implement the IABLogon::CompareEntryIDs method. See Comparing Address Book Entries.
Create messaging users | 1. Provide a list of creation templates in a one-off table by supporting the PR_CREATE_TEMPLATES property. See Implementing a Container One-Off Table. 2. Implement the IABContainer::CreateEntry method. See Adding Address Book Entries.
Copy messaging users | Implement the IABContainer::CopyEntries method. See Copying Address Book Entries.
Remove messaging users | Implement the IABContainer::DeleteEntries method. See Removing Address Book Entries.
Provide summary information about messaging users | Support the container property PR_CONTAINER_CONTENTS. See Contents Tables.
Provide detailed information about messaging users | Support the PR_DETAILS_TABLE property on messaging users and distribution lists. See Displaying Recipient Information and Display Tables.
Provide detailed information about a container | Support the PR_DETAILS_TABLE property on the container. See Displaying Recipient Information and Display Tables.
Provide a hierarchical list of containers | Support the container property PR_CONTAINER_HIERARCHY. See Hierarchy Tables.
Support messaging user properties | Implement the IMailUser interface.
Resolve ambiguous names | 1. Support the PR_ANR property restriction. 2. Optionally implement the IABContainer::ResolveNames method. See Implementing Name Resolution.


Opening Address Book Entries

When a client or provider has requested that one of your objects be opened, MAPI calls your provider's IABLogon::OpenEntry method. MAPI determines that the entry identifier representing the target object belongs to your provider by examining the MAPIUID portion of the entry identifier and matching it to the MAPIUID that your provider registered in the call to IMAPISupport::SetProviderUID. MAPI then calls your OpenEntry method. Your provider must respond by retrieving the corresponding object — a container, distribution list, or messaging user.

A NULL entry identifier indicates a request to open the address book provider's root container. Clients open the root container to access its hierarchy table and its recipients. Address book providers that only supply templates for creating one-off recipients do not support the OpenEntry call for the root container.

To implement IABLogon::OpenEntry
  1. Check that the entry identifier is a valid identifier that your provider supports. If it is not a valid entry identifier, return MAPI_E_INVALID_ENTRYID.
  2. Check the flag that is passed in with the ulFlags parameter. If MAPI has passed in MAPI_MODIFY and your provider does not allow its objects to be modified, fail and return the MAPI_E_ACCESS_DENIED error value.
  3. Check that the interface requested in the lpInterface parameter is valid for the type of object your provider has been asked to open. If an invalid parameter has been passed in, fail and return the MAPI_E_INTERFACE_NOT_SUPPORTED error value.
  4. If the cbEntryID parameter is zero, this is a request to open your provider's root container. Create the root container and return a pointer to its IABContainer interface implementation.
  5. If your provider implements several logon objects, each with its own registered MAPIUID, map the MAPIUID contained in the entry identifier with the appropriate logon object.
  6. Determine which type of object the entry identifier represents: a messaging user, distribution list, or container belonging to your provider or a one-off messaging user or distribution list so that the appropriate value can be set for the lpulObjectType parameter.
  7. Create the object of the appropriate type and set the following basic properties:

    PR_DISPLAY_TYPE

    PR_ENTRYID

    PR_OBJECT_TYPE

    PR_ADDRTYPE

    Calculate PR_EMAIL_ADDRESS and PR_DISPLAY_NAME from information in the entry identifier.

  8. Return a pointer to the interface implementation for the object.


Comparing Address Book Entries

Your provider's IABLogon::CompareEntryIDs implementation compares the entry identifiers for two of your provider's objects. MAPI calls this method after determining that the two entry identifiers contain your provider's registered MAPIUID. Therefore, your CompareEntryIDs method need not check that the entry identifiers passed in for the lpEntryID1 and lpEntryID2 parameters belong to your provider.

Calling IABLogon::CompareEntryIDs is equivalent to retrieving the PR_RECORD_KEY property for each of the two objects and comparing them directly.

To implement CompareEntryIds
  1. Check the type of the entry identifiers passed in if your provider stores that information. For example, one entry identifier might belong to a messaging user while the other might belong to a distribution list. If the types do not match, set the contents of the lpulResult parameter to FALSE and return.
  2. Compare the sizes of the two entry identifiers. If they are not the same, set the contents of the lpulResult parameter to FALSE and return.
  3. Check that the size of the entry identifiers is the correct size for their type. If not, set the contents of the lpulResult parameter to FALSE and return the error value MAPI_E_UNKNOWN_ENTRYID.
  4. Check if the entry identifiers are the same. If they compare equally, set the contents of the lpulResult parameter to TRUE and return. Otherwise, set it to FALSE before returning.
  5. If your provider is comparing a short-term entry identifier with a long-term identifier, they should compare equally.


Adding Address Book Entries

To add a messaging user or distribution list to a container, a client calls IAddrBook::NewEntry or a provider calls IMAPISupport::NewEntry with the entry identifier of the target container in the lpEIDContainer parameter. MAPI in turn calls the container's IABContainer::CreateEntry method to create the entry using a one-off template from a one-off table. A one-off template allows the client to create a new recipient of a particular type. Most of the fields are editable. The template pointed to by the lpEntryID parameter might be one that your provider supplies or it might be a template from a foreign provider, if your provider supports foreign templates. Implementations of CreateEntry for providers that can create recipients from a foreign template are always more complex than implementations for providers that cannot.

To implement IABContainer::CreateEntry
  1. Determine the type of entry identifier specified by the lpEntryID parameter.
  2. If the entry identifier represents a template for a messaging user, distribution list, or address book container owned by your provider:
    1. Create and initialize the appropriate object. Your provider can set some initial properties if desired. These properties depend on the type of recipient being created.
    2. Return a pointer to the object's implementation in the contents of the lppMAPIPropEntry parameter.
  3. If the entry identifier represents a template for a foreign provider:
    1. Call IMAPISupport::OpenEntry to open the foreign object.
    2. Call the object's IMAPIProp::GetProps method, passing NULL for the property tag array, to retrieve its properties.
    3. Edit the property value array returned from GetProps by changing the property tag to PR_NULL for all properties that will not apply to the new object and should not be transferred.
    4. Create an entry identifier for the new object.
    5. Create a new object of the appropriate type, either messaging user or distribution list.
    6. Initialize the new object by setting default properties.
    7. Check whether or not the foreign object supports the PR_TEMPLATEID property.
    8. If the foreign object supports PR_TEMPLATEID, call IMAPISupport::OpenTemplateID to retrieve a property object interface from the foreign provider and set the contents of the lppMAPIPropEntry parameter to the foreign property object implementation.
    9. If the foreign object does not support PR_TEMPLATEID, set the contents of the lppMAPIPropEntry parameter to your provider's implementation of the new object.
    10. Call the IMAPIProp::SetProps method of the object pointed to by the lppMAPIPropEntry parameter to set the appropriate properties from the foreign object.


Copying Address Book Entries

Your container's IABContainer::CopyEntries method is called when one or more recipients from the same or another container are to be copied into this container. CopyEntries has four input parameters: an array of entry identifiers representing the recipients to be copied, a window handle for the progress indicator, a progress object pointer, and a flags value. Your provider should display progress if the AB_NO_DIALOG flag is not set and use the progress object from the lpProgress parameter if it is not NULL. If lpProgress is NULL, call IMAPISupport::DoProgressDialog to use the MAPI progress object. For more information about displaying progress, see Displaying a Progress Indicator.

In addition to AB_NO_DIALOG to suppress a progress indicator, one of two other flags can be set to request a type of duplicate entry checking: CREATE_CHECK_DUP_LOOSE or CREATE_CHECK_DUP_STRICT. The CREATE_CHECK_DUP_LOOSE and CREATE_CHECK_DUP_STRICT flags are only suggestions as to how your provider determines duplicate entries and can be ignored. MAPI suggests that your provider implement support for these flags as follows.

Duplicate entry flag | Suggested implementation
CREATE_CHECK_DUP_LOOSE | Check if the display name in the entry to be created matches the display name of an entry already in the container.
CREATE_CHECK_DUP_STRICT | Check if both the display name and the search key in the entry to be created match the display name and search key of a container entry.

The last flag, CREATE_REPLACE, indicates that the new entry should replace the existing one if your provider has determined that an entry to be created is a duplicate of an entry already in your container.

If your provider is a personal address book, include the PR_DETAILS_TABLE property in every copy operation. Including the details display table of a copied recipient allows your container to display the details of the recipient rather than having to call the original container to create the display.

To implement IABContainer::CopyEntries
  1. Determine if each entry identifier in the lpEntries parameter is in a format that your provider handles and if it is not, fail and return MAPI_E_INVALID_ENTRYID.
  2. If an entry identifier represents a messaging user, distribution list, or container that your provider handles:
    1. Call your IMAPISupport::OpenEntry method to open the corresponding recipient.
    2. Copy the recipient to your container.
  3. If the entry identifier represents a foreign recipient:
    1. Call your container's IABContainer::CreateEntry method to create a new recipient.
    2. Set initial properties on the new recipient.
  4. Call the new object's IMAPIProp::SaveChanges method to save it.
  5. Update the container's contents table to reflect the new recipient.
  6. Call IMAPISupport::Notify to send a table notification to registered clients.


Removing Address Book Entries

Your container's IABContainer::DeleteEntries method is called to remove one or more recipients. DeleteEntries has two parameters: an array of entry identifiers representing the recipients to be deleted and a reserved flags value. Deleting a recipient affects the contents table of your container; in addition to deleting the recipient, your container must delete the contents table row that represents the recipient. When the row has been removed from the table, your container must issue a table notification to each registered client.

To implement IABContainer::DeleteEntries
  1. Delete each recipient represented by the entry identifier from your container.
  2. If your container's contents table is open:
    • Send an fnevTableModified notification with the ulTableEvent member set to TABLE_ROW_DELETED to registered clients for each deleted contents table row. If your provider uses the notification utility, call IMAPISupport::Notify to send these notifications.
    • If your provider supports object notifications, also send an fnevObjectDeleted notification.


Implementing Name Resolution

Address book providers are responsible for supporting name resolution — the process of associating an entry identifier with a display name. Clients initiate name resolution when they call IAddrBook::ResolveName to ensure that each member of an outgoing message's recipient list corresponds to a valid address.

Your provider can support name resolution by:

  • Supporting the PR_ANR property restriction, a requirement for all address book containers.
  • Implementing the IABContainer::ResolveNames method, an option for all address book containers.

If you choose to support IABContainer::ResolveNames, attempt to locate an exact match for each unresolved display name in the ADRLIST structure passed in with the lpAdrList parameter. You can identifiy an unresolved display name because it is missing the PR_ENTRYID property in the property value array in its aEntries member of the ADRLIST structure. Ignore any entries that have zero properties associated with them.

Report the result of your attempt at resolution in the lpFlagList parameter, an array of flags that corresponds to the array of display names in lpAdrList. The flags are positional such that the first flag corresponds to the first aEntries member in the ADRLIST structure, the second flag corresponds to the second aEntries member, and so on.

There are three possible results for each unresolved entry:

  • No match was found, meaning that none of the entries in your container entries match the entry in the ADRLIST structure. Set the corresponding entry in the lpFlagList parameter to MAPI_UNRESOLVED.
  • Several matches can be found, meaning that there are multiple container entries that match the entry in the ADRLIST structure. Set the corresponding entry in the lpFlagList parameter to MAPI_AMBIGUOUS. Do not change the number of entries in the ADRLIST structure.
  • An exact match can be found, meaning that there is only one container entry that matches the entry in the ADRLIST structure. Set the corresponding member in the lpFlagList parameter to MAPI_RESOLVED and add the entry identifier to the array of properties associated with the ADRLIST entry.

If you choose not to support IABContainer::ResolveNames, return MAPI_E_NO_SUPPORT from your implementation.

All address book providers are required to support ambiguous name resolution — the PR_ANR property restriction — on their containers' contents tables. To provide this support, handle the PR_ANR restriction in your implementation of IMAPITable::Restrict by performing a "best guess" type of search, matching against one or more particular properties that make sense for your provider. You can choose to use the same property or properties every time, such as PR_DISPLAY_NAME or PR_ACCOUNT, or allow an administrator to choose from a list of acceptable properties.

Although most providers supply their own contents table implementation, you can customize the implementation supplied by MAPI through the CreateTable function. However, because the MAPI implementation does not support restrictions of any kind, you must create a wrapper object to include a customized version of Restrict that intercepts the call.


Displaying Recipient Information

MAPI provides a common dialog box for showing recipient details. This dialog box is modal; a modeless version is provided for in the interface but is unsupported. The details dialog box is created from a display table and an IMAPIProp implementation. The display table describes the appearance of the details display and the IMAPIProp implementation controls the data for the recipient. Your provider is responsible for supplying the display table and the IMAPIProp implementation for each recipient.

The easiest way to create the display table is to define a DTPAGE structure and call BuildDisplayTable. However, some providers, specifically read-only providers that allow the creation of one-off recipients, use IPropData. The IMAPIProp implementation can be any type of property object.

There are two methods for invoking this dialog box: IAddrBook::Details and IMAPISupport::Details. When your provider calls one of these methods to request details for a recipient, MAPI first opens the recipient by calling its container's IMAPIContainer::OpenEntry method. Next it calls the recipient's IMAPIProp::OpenProperty method to request the PR_DETAILS_TABLE property. PR_DETAILS_TABLE is the property that represents a recipient's details display table.

The IPropData interface can be used to monitor changes on display table controls as described in the following procedure.

To monitor changes to a control
  1. Before the user gains access to the control, call IPropData::HrSetObjAccess to set the control's access to IPROP_CLEAN.
  2. Allow the user to work with the dialog box.
  3. When the user has finished, call IPropData::HrGetPropAccess to retrieve the current access level of the control.
  4. If the access level is IPROP_DIRTY, the user has modified the control. Your provider should:
    • Call IPropData::HrSetPropAccess to set the access level back to IPROP_CLEAN.
    • Call the property data object's IMAPIProp::GetProps method to retrieve the changed property and update it by calling IMAPIProp::SetProps.
  5. If the access level is still IPROP_CLEAN, the control has not been modified.

For more information about creating display tables, see Display Tables.


Optional Features for Address Book Providers

There are many optional features for address book providers. Some of the more commonly implemented features include:

  • Acting as a foreign provider by allowing entries from one of your containers to be added to another provider's container.
  • Acting as a host provider by adding entries from another provider to one of your containers.
  • Advanced searching.
  • Prefix scrolling through contents tables.
  • Support for distribution lists.
  • Support for event notification.

The following table briefly describes these optional features and how you implement them:

Feature | How to implement
Supply templates for creating entries for message recipient lists | Implement the IABLogon::GetOneOffTable method. See One-Off Tables and Implementing One-Off Tables.
Group recipients into a named unit | Support the properties of distribution lists by implementing the IDistList interface.
Act as a foreign address book provider by allowing entries to be added to a container in another provider | Support binding code to data in the host provider by: 1. Supporting the PR_TEMPLATEID property on messaging users and distribution lists. See Address Book Identifiers. 2. Implementing the IABLogon::OpenTemplateID method. See Acting as a Foreign Address Book Provider.
Acting as a host address book provider by inserting entries from another provider | Support binding data to code from a foreign provider by calling the IMAPISupport::OpenTemplateID method. See Acting as a Host Address Book Provider.
Prefix scrolling | Support restrictions on container contents tables. See About Restrictions.
Advanced searching in a container | Support the PR_SEARCH property on containers. See Implementing Advanced Searching.
Event notification | Implement the IABLogon::Advise and IABLogon::Unadvise methods. See Event Notification in MAPI and Supporting Event Notification.

For event notification, your IABLogon::Advise method will be called by MAPI when a client calls IAddrBook::Advise to register for notifications on any one of your containers, messaging users, or distribution lists. However, because supporting event notification is optional, you can return MAPI_E_NO_SUPPORT from these methods. However, MAPI does recommend that you at least support notifications on your contents tables and encourages you to support all types of object notification except for fnevSearchComplete and the fnevCriticalError event to add value.


Acting as a Foreign Address Book Provider

A foreign provider is an address book provider that:

  • Assigns template identifiers for its recipients.
  • Supports the IABLogon::OpenTemplateID method.
  • Supplies code for maintaining recipients that exist in the containers of other address book providers known as host providers. The code involves a property object, typically an IMAPIProp interface implementation, that wraps a property object from the host provider.

Acting as a foreign provider is an optional role; not all providers need to support template identifiers and their related code. Implement your provider as a foreign provider if you want to maintain control over recipients that host providers create using templates supplied by your provider.

The format that your provider uses for its entry identifiers can also be used for its template identifiers. Template identifiers must include your provider's registered MAPIUID to allow MAPI to successfully bind recipients to the appropriate providers.

MAPI calls your provider's IABLogon::OpenTemplateID method when a host provider calls IMAPISupport::OpenTemplateID. The host provider passes the template identifier of the recipient in the lpTemplateID parameter in its call to IMAPISupport::OpenTemplateID. MAPI determines that the template identifier belongs to your provider by matching the MAPIUID in the template identifier with the MAPIUID that your provider registered at logon time. MAPI then forwards the host provider's call to your provider through the IABLogon::OpenTemplateID method.

The host provider also passes a pointer to its property object implementation for the recipient in the lpMAPIPropData parameter, an interface identifier in the lpInterface parameter that corresponds to the type of interface implementation passed in lpMAPIPropData, and an optional flag, FILL_ENTRY. Your provider is expected to return in the lppMAPIPropNew parameter a pointer to a property object implementation of the type specified in lpInterface. The returned pointer can either be to the wrapped property object implemented by your provider or to the object supplied by the host provider in lpMAPIPropData. Your provider should return a wrapped property object pointer when:

  • The recipient's display table contains list box controls.
  • The e-mail address for the recipient must be assembled from data in multiple display table controls.
  • Your provider issues display table notifications.

The FILL_ENTRY flag indicates to your provider that the host provider wants all the properties of the recipient to be updated. Your provider is required to fulfill this request.

When a host provider calls your provider's OpenTemplateID method, your provider might:

  • Periodically update the data for a copied entry.
  • Keep a copied entry synchronized with its original, such as when an address book entry is copied to the personal address book.
  • Implement functionality that cannot be implemented by the host provider, such as dynamically populating list boxes in the copied entry's details table from data on a server.
  • Control the interaction among properties in a copied entry or instantiated template. For example, computing PR_EMAIL_ADDRESS from other properties displayed in the details table.

The first two items are examples of tasks that do not require your provider to supply a wrapped property object — an implementation of IMAPIProp that is based on the host provider's implementation. Your provider can simply update the properties as necessary and return, setting the lppMAPIPropNew parameter to point to the pointer passed in by the host provider in the lpMAPIPropData parameter.

The second two tasks require that your provider return to the host provider a property object that wraps the host provider's object with additional functionality, such as the ability to display a property sheet for the entry. This property object will either be a messaging user or distribution list, depending on the type of object passed in by the host provider in the lpMAPIPropData parameter and indicated by the interface identifier in the lpInterface parameter. If the lpMAPIPropData parameter points to a messaging user, your provider's wrapped property object must be an IMailUser implementation. If lpMAPIPropData points to a distribution list, it must be an IDistList implementation.

Your provider's wrapped property object intercepts IMAPIProp method calls to perform context-specific manipulation of the host provider's recipient — the object it is wrapping. MAPI only has one requirement for wrapped property objects: all calls to IMAPIProp::OpenProperty requesting the PR_DETAILS_TABLE property should be passed to the host provider. Your provider's implementation can use the returned table to intercept display table notifications or to add its own if necessary.

The following list includes tasks that are typically implemented in the wrapped property object implemented by foreign providers:

  • Preprocessing and postprocessing property values for the host recipient in IMAPIProp::GetProps.
  • Handling details display table controls such as buttons and list boxes in IMAPIProp::OpenProperty.
  • Validating or manipulating property values for the host recipient in IMAPIProp::SetProps.
  • Computing required properties such as PR_EMAIL_ADDRESS and verifying that all of the necessary properties have been set before saving the host recipient in IMAPIProp::SaveChanges.

To implement IABLogon::OpenTemplateID
  1. Check if the template identifier passed in with the lpTemplateID parameter is valid and is in a format that your provider recognizes. If it is not, fail and return MAPI_E_INVALID_ENTRYID.
  2. Create an object of the type indicated by the template identifier, either a messaging user, distribution list, or one-off recipient.
  3. Call the IUnknown::AddRef method in the host provider's property object, the object pointed to by the lpMAPIPropData parameter.
  4. If the ulTemplateFlags parameter is set to FILL_ENTRY:
    1. If the new object is a messaging user or distribution list:
1. Retrieve all of the properties of the new object, possibly by calling its IMAPIProp::GetProps method.
2. Call the host provider's IMAPIProp::SetProps method to copy all of the retrieved properties to the host provider's property object.

  2. If the new object is a one-off recipient, call the host provider's IMAPIProp::SetProps method to set the following properties:
· PR_ADDRTYPE to the address type handled by your provider.
· PR_TEMPLATEID to the template identifier from the lpTemplateID and cbTemplateID parameters.
· PR_DISPLAY_TYPE to DT_MAILUSER or DT_DISTLIST, as appropriate.

  5. Set the contents of the lppMAPIPropNew parameter to point to either your provider's new object or the property object passed in with the lpMAPIPropData parameter, depending on whether your provider determines a wrapped object is necessary.
  6. If a critical error occurs, such as a network failure or an out of memory condition, return the appropriate error value. This value should get propagated to the client with the appropriate MAPIERROR structure, a task performed by the host provider.


Acting as a Host Address Book Provider

A host provider is an address book provider that includes recipients from other providers in its containers and relies on the implementation of the recipients by the other providers to partially control their maintenance. A host provider uses the template identifiers of these foreign recipients to bind the data for these recipients to code in the foreign provider. This binding process is initiated when your provider retrieves the PR_TEMPLATEID property of a recipient and passes it in a call to IMAPISupport::OpenTemplateID.

When your provider calls IMAPISupport::OpenTemplateID, MAPI matches the MAPIUID within the template identifier with a MAPIUID registered by a provider and calls the provider's IABLogon::OpenTemplateID method. The foreign provider might return a pointer to your provider's property object or its own property object implementation, an implementation that wraps your provider's object. The returned pointer is placed in the contents of the lppMAPIPropNew parameter.

Your provider can choose whether or not to call IMAPISupport::OpenTemplateID with the FILL_ENTRY flag set. Set this flag when the recipient is being created or when a long time has passed since your provider has refreshed the recipient's properties. A common use of the FILL_ENTRY flag is to keep a recipient in your provider synchronized with the original. Implementing this type of synchronization schedule enhances performance.

To keep a foreign recipient synchronized
  1. Determine an appropriate interval for periodic updates.
  2. Timestamp each call to IMAPISupport::OpenTemplateID.
  3. Evaluate whether or not it is necessary to perform a full update based on the amount of time that has expired since the last call. If a full update is necessary, call IMAPISupport::OpenTemplateID with the FILL_ENTRY flag. If it is not necessary, do not set the flag on the call.

When a client makes a request for one of the copied recipient's properties, your provider can choose whether to handle the request itself or use the code supplied by the foreign provider. Your provider can expect the foreign provider to intercept most, if not all, calls to IMAPIProp except for IMAPIProp::OpenProperty. A call to OpenProperty requesting the PR_DETAILS_TABLE property is always forwarded to your provider.

To access template identifier code
  1. Open the recipient and call its IMAPIProp::GetProps method to retrieve the PR_TEMPLATEID property. If GetProps fails because PR_TEMPLATEID is unavailable, the foreign provider does not support a template identifier and related code for this recipient. Your provider will need to use its implementation of the recipient for all maintenance.
  2. If the template identifier is returned from GetProps, pass it and a pointer to the recipient's IMAPIProp implementation in a call to the IMAPISupport::OpenTemplateID method. Set the FILL_ENTRY flag if most or all of the recipient's properties need to be updated, such as at creation time or if they have not been updated for a while.
  3. If OpenTemplateID returns the foreign provider's IMAPIProp implementation, return to the client a pointer to this implementation.
  4. If OpenTemplateID does not return an implementation, typically because the foreign provider is not in the profile, return to the client a pointer to your provider's IMAPIProp implementation. The client should be able to work with the object's properties using either interface.


Implementing Advanced Searching

Some address book containers support an advanced searching capability that allows clients to search on properties other than PR_DISPLAY_NAME. To support advanced searches, your provider must implement a special container that is accessible through the PR_SEARCH property of your other containers. PR_SEARCH contains a container object that provides access to a display table that describes the dialog box used to enter and edit the advanced search criteria.

To support advanced searching
  1. Define a property for each of your search criteria.
  2. In the section of code in your container's IMAPIProp::OpenProperty method that handles the PR_SEARCH property:
    1. Check that the client is requesting the IMAPIContainer interface. If an inappropriate interface is being requested, fail and return MAPI_E_INTERFACE_NOT_SUPPORTED.
    2. Create a new search object that supports the IMAPIContainer interface.
  3. At this point, a call will be made to your search container's IMAPIProp::OpenProperty method to retrieve its PR_DETAILS_TABLE property. Your provider must supply a display table, typically through a call to BuildDisplayTable, that describes the container's advanced search dialog box.
  4. MAPI displays the search dialog box, allowing the user to enter the appropriate criteria. When the user has finished, MAPI calls the container's IMAPIProp::SetProps method to store the search criteria.
  5. A call will be made to request your search container's contents table. Populate the contents table with all of the entries in the container that match the criteria.


Implementing One-Off Tables

Your provider might implement one or more one-off tables. A one-off table is a summary list of one-off templates used to create recipients, either directly into a container or into the recipient list of an outgoing message. A one-off template is a form users employ for entering data relevant to a particular type of address. When the user is finished working with the template, your provider creates the new recipient and adds it to the message. Typically each template handles a single address type. However, it is possible for a template to handle multiple types or for multiple templates to handle the same type.

Your provider must support the OpenEntry method for each template that it includes in the one-off table. The implementation of OpenEntry should retrieve a display table for the template. MAPI uses the display table to make the template visible to the user.

Although most of the rows in one-off tables represent templates, some of the rows can be used to categorize, or group, templates. Whether or not a row in a one-off table represents a template is indicated by the value of its PR_SELECTABLE column. Rows that represent templates have the PR_SELECTABLE column set to TRUE; rows that do not represent templates have it set to FALSE.

MAPI defines three types of one-off tables:

  • A one-off table that reflects the templates that an individual container supports
  • A one-off table that reflects all of the templates that your provider supports
  • A one-off table that reflects all of the templates that all of the providers in the profile support plus some that MAPI supports

The first two types are implemented by providers that support the creation recipients, either onto a message or into a container. Your provider can include the same set or a different set of templates in its one-off tables. The main difference between the two types is that your provider table should include templates for creating recipients that can be used on outgoing messages and your container table should include templates for creating recipients to be added to your container. A container may only support a restricted set of templates, but the provider one-off table should include every template the provider supports.

The third type of one-off table is implemented by MAPI; providers gain access to it by calling IMAPISupport::GetOneOffTable. The MAPI one-off table is the union of all of the provider tables; it includes every template supported by every provider in the profile. It also includes templates supported by MAPI. Your provider can use this table in place of the table requested for a container. However, the templates in this table can also be used for creating recipients for outgoing messages.


Implementing a Provider One-Off Table

MAPI calls your provider's IABLogon::GetOneOffTable method when the user of a client application adds a recipient to an outgoing message. Typically, the types of addresses requested are unique to your messaging system. If your provider supports recipient creation, it must supply a one-off table that exposes templates for every type of supported recipient address. If your provider does not support recipient creation, return MAPI_E_NO_SUPPORT from the GetOneOffTable call.

MAPI will typically keep your provider's one-off table open for the lifetime of the session, releasing it only when a client calls either the subsystem's or address book's IMAPIStatus::ValidateState method. MAPI registers for notifications on this table so that if templates are added or deleted, these changes can be reflected to the user.

To implement IABLogon::GetOneOffTable
  1. Check the value of the flags parameter, ulFlags. If the MAPI_UNICODE flag is set and your provider does not support Unicode, fail and return MAPI_E_BAD_CHARWIDTH.
  2. Check if your provider's one-off table has already been created. Because one-off tables are typically static, your provider never has to go through the creation process more than once. If a table already exists, return a pointer to it.
  3. If a one-off table does not yet exist, call CreateTable to create one.
  4. Set the following properties for the columns in your table rows:
    • PR_DISPLAY_NAME to the name of the type of recipient that the template can create.
    • PR_ENTRYID to the entry identifier for the one-off template.
    • PR_DEPTH to indicate the hierarchy level in the one-off table display.
    • PR_SELECTABLE to TRUE to indicate if the row represents a template and FALSE otherwise.
    • PR_ADDRTYPE to the type of address created by the template.
    • PR_DISPLAY_TYPE to DT_MAILUSER or another value that indicates the type of display for the template.
    • PR_INSTANCE_KEY to a unique binary value.
  5. Call ITableData::HrModifyRow to modify the table directly.
  6. Call ITableData::HrGetView to create an IMAPITable interface implementation to return to the caller.


Implementing a Container One-Off Table

To access the one-off table belonging to one of your containers, MAPI calls the container's IMAPIProp::OpenProperty method to open the PR_CREATE_TEMPLATES property with the IMAPITable interface. Your container is asked to return its one-off table when a client application is trying to add a recipient to the container. If the container allows any recipients, your provider can either return its own table implementation or call IMAPISupport::GetOneOffTable to return the MAPI implementation.

The set of templates in the container one-off table should reflect the type of recipients that the particular container can hold. Typically, this includes one or two templates, templates for creating an individual messaging user or a distribution list. The entry identifiers for these templates are held in the PR_DEF_CREATE_MAILUSER and PR_DEF_CREATE_DL properties. However, containers are by no means limited to these types of entries. They can hold other types of recipients or non-recipient entries such as directories.


Developing a Transport Provider

You should be familiar with the MAPI subsystem's architecture, the C++ language, and with writing dynamic-link libraries (DLLs) for the various Windows platforms before developing a transport provider.

For information about implementation of features necessary for TNEF and remote transport providers, see Developing a TNEF-Enabled Transport Provider and Developing a Remote Transport Provider.


What is a Transport Provider

A transport provider is a dynamic-link library (DLL) which acts as an intermediary between the MAPI subsystem and one or more underlying messaging systems. A messaging system is some specific mechanism by which messages are sent and received. Some examples of messaging systems are:

  • A shared network file system that the transport provider writes messages to directly.
  • A TCP/IP network interface that the transport provider uses to connect to a messaging server.
  • An online service that users dial into.
  • A host-based messaging or office automation system.
  • A set of remote procedure calls to a messaging server.
  • Anything that can be used to transfer data from one computer to another.

A transport provider DLL must conform to the interface specified by MAPI. As a transport provider developer, you will implement this interface in terms of the functionality present in the messaging system.


Types of Transport Providers

All transport providers support a range of standard features, such as:

  • Providing proper security for the underlying messaging system.
  • Sending and receiving messages from the underlying messaging system.
  • Exposing the address types the transport providers support so the MAPI spooler and client applications can use them appropriately.
  • Accepting delivery for specific recipients.

In addition, MAPI supports two specialized types of providers for specific messaging systems.

Transport type | Added functionality
Remote Transport | Enables interoperabilty with remotely connected clients.
TNEF Transport | Allows MAPI properties to be preserved on messaging systems that do not support them.

Remote transports are used by messaging clients that are using low-bandwidth network connections. The most common example is a client operating over a modem link. Remote transports implement the IMAPIFolder : IMAPIContainer interface in addition to the basic functionality implemented by all transports. The IMAPIFolder interface makes it possible for client applications to selectively download messages from a remote message server based on header information at a user's request. Remote transports make themselves known to clients as remote transports by registering themselves in the MAPI status table. For information on implementing remote transports, see Developing a Remote Transport Provider.

TNEF transports are used for translating messages between messaging systems that support different sets of MAPI properties. TNEF transports use the MAPI ITnef : IUnknown interface to convert any properties that the destination system cannot represent directly into a binary data stream that can be attached to the message. Later, another TNEF transport can use ITnef to decode the data stream and make the original MAPI properties available to client applications. Additionally, TNEF support is required if your transport needs to support custom message classes. For information on implementing TNEF transports, see Developing a TNEF-Enabled Transport Provider.

If your transport provider is not one of these types, you will have to implement it with the basic MAPI functions and networking functions available on your target platform.


Transport Provider's Role in the MAPI Subsystem

Transport provider dynamic-link libraries (DLLs) provide the interface between the MAPI spooler and that part of a messaging system responsible for message sending and receiving. The MAPI spooler and the transport provider work together to handle the responsibilities of sending a message or receiving a message. The MAPI spooler loads the transport provider DLL when it is first used and releases it when it is no longer needed. Multiple transports can be installed on the same system, but MAPI supplies the one spooler required.

Client applications do not typically communicate directly with the transport provider; rather, clients submit messages through a store provider, and the MAPI spooler sends outgoing messages to the appropriate transport provider and delivers incoming messages to the appropriate message store. The MAPI spooler does its work and makes its calls to transport providers when foreground applications are idle. After optionally displaying dialog boxes when the transport provider is first logged on, transport providers operate in the background unless called by the client to flush send and receive queues.

Transport providers have the following responsibilities in a MAPI messaging system:

  • Register the address types they can accept with the MAPI spooler so the MAPI spooler can submit messages to the appropriate transport provider depending on the destination address of the messages. One transport provider can register more than one address type. Transport providers can also register specific recipients' addresses with the MAPI spooler. Messages addressed to one of these addresses will be submitted to the transport provider that registered this address with the MAPI spooler. For more information, see Transport Provider-MAPI Spooler Operational Model.
  • Deliver incoming messages to the MAPI spooler. Depending on the nature of the messaging system, a transport provider can either directly notify the MAPI spooler when a new message arrives, or can request that the MAPI spooler poll the transport provider periodically to check for new messages.
  • Convert MAPI message properties to and from message properties native to the messaging system. For example, the transport provider might have to convert the sender's and recipients' addresses in an outgoing message to a form that is acceptable to the messaging system. Some messaging systems do not support all of the MAPI message properties. For information on preserving MAPI message properties when delivering messages to a messaging system, see Developing a TNEF-Enabled Transport Provider.
  • Register message and recipient options specific to the transport provider.
  • Perform any verification of credentials required by the messaging system.
  • Access outbound messages using the message object passed to it by the MAPI spooler.
  • Translate message format as required by the underlying messaging system.
  • Notify the MAPI spooler which recipients of an outgoing message the transport provider has accepted responsibility for handling by setting the PR_RESPONSIBILITY property for those recipients.
  • Inform the MAPI spooler when an incoming message needs to be handled.
  • Pass incoming message data to the MAPI spooler by using message objects.
  • Assign values to all required MAPI message properties on incoming messages.
  • Delete the message from the underlying messaging system after delivery, if necessary.
  • Provide status information for the MAPI spooler and client applications.

The following illustration shows a transport provider's role with respect to the other components of the MAPI architecture.


Transport Provider-MAPI Spooler Operational Model

Transport provider initialization, startup, processing, shutdown and deinitialization are accomplished by a series of calls from the MAPI spooler to the transport provider. The calls are sequenced as follows:

  1. The MAPI spooler calls the XPProviderInit function, passes a support object, gets the provider object, and checks that the provider and MAPI spooler support a compatible range of MAPI version numbers.
  2. The MAPI spooler calls the IXPProvider::TransportLogon method of the XPProvider object. A session is established between the MAPI spooler and the transport with the credentials in the current section of the profile. The provider returns a logon object.
  3. The MAPI spooler calls the IXPLogon::AddressTypes method. The transport returns a list of the unique identifiers (UIDs) and e-mail address types it will accept.
  4. The MAPI spooler calls the IXPLogon::RegisterOptions method for recipient options. The transport returns a list of the available per-recipient options for any of the e-mail address types that it returned in the IXPLogon::AddressTypes call.
  5. The MAPI spooler calls RegisterOptions for message options. The transport returns a list of the available per-message options for any of the e-mail address types that it returned in the IXPLogon::AddressTypes call.
  6. The transport calls the IMAPISupport::ModifyStatusRow method to create its row in the MAPI status table.
  7. The MAPI spooler calls the IXPLogon::TransportNotify method to enable message transmission and reception.
  8. If requested by the transport provider in its return for the TransportLogon call, the MAPI spooler periodically calls the IXPLogon::Idle method. Idle processing is useful if the transport provider needs to poll the underlying messaging system for new messages or perform other low-priority tasks.
  9. The MAPI spooler and transport send and receive messages (see Message Submission Model and Message Reception Model). The MAPI spooler services transport requests and calls on support, message, and attachment objects.
  10. The MAPI spooler calls the TransportNotify method to disable message transmission and reception.
  11. The MAPI spooler releases the logon and provider objects. See IXPProvider::Shutdown.


Message Submission Model

Message submission is accomplished by a series of calls from the MAPI spooler to the transport provider. The calls are sequenced as follows:

  1. The MAPI spooler calls IXPLogon::SubmitMessage, passing in an IMessage instance, to begin the process.
  2. The transport provider then places a reference value — a transport-defined identifier used in future references to this message — in the location referenced in SubmitMessage.
  3. The transport provider accesses the message data by using the passed IMessage instance. For each recipient in the passed IMessage for which it accepts responsibility, the transport provider sets the PR_RESPONSIBILITY property, and then returns.
  4. The transport provider can use the IMAPISupport::StatusRecips method to indicate if it recognizes any recipients that cannot be delivered to, or to create a standard delivery report. StatusRecips is a convenience for transport providers that have determined that some of the recipients cannot be delivered to or have received delivery information from their underlying messaging system that the user or client application might find useful.
  5. The MAPI spooler's call to IXPLogon::EndMessage is the final responsibility hand-off for the message from the MAPI spooler to the transport provider.
  6. The MAPI spooler can use IXPLogon::TransportNotify to cancel message processing during the SubmitMessage or EndMessage calls.


Message Reception Model

The transport provider controls whether the MAPI spooler must poll it for incoming mail or whether it performs a callback to the MAPI spooler when new mail arrives. The transport provider sets the SP_LOGON_POLL flag when it returns from IXPProvider::TransportLogon to request polling. Otherwise, the transport uses IMAPISupport::SpoolerNotify when incoming mail is available. After learning that incoming mail is available, the MAPI spooler opens a new message and asks the transport provider to store the received message properties into the message.

This process works as follows:

  1. Available messages are indicated by either the transport provider calling IMAPISupport::SpoolerNotify or by the MAPI spooler calling IXPLogon::Poll.
  2. The MAPI spooler calls IXPLogon::StartMessage to initiate the process.
  3. The transport provider places a reference value in the location referenced in StartMessage. These reference values allow the transport provider and the MAPI spooler to keep track of which message is being processed when there are multiple messages to deliver.
  4. The transport provider stores the message data into the passed IMessage instance.
  5. The transport provider calls the IMAPIProp::SaveChanges method on the IMessage instance and returns from StartMessage.
  6. The MAPI spooler calls IXPLogon::TransportNotify if it must stop message delivery.

Note If a transport provider must deliver a large number of messages and the transport provider is using IMAPISupport::SpoolerNotify instead of IXPLogon::Poll, care should be taken not to call SpoolerNotify too frequently in order not to deprive other transport providers of CPU time. The MAPI spooler does have logic to prevent this from happening, but in general the interval between SpoolerNotify calls should be longer than the time it takes your transport provider to process one message.

Also, the MAPI spooler may not process an incoming message immediately. The MAPI spooler may ask the transport provider to perform other tasks before it receives the incoming message.


Required Functionality for Transport Providers

Every MAPI transport provider must:

  • Follow the general guidelines for working with MAPI and other service providers as described in MAPI Programming Basics and Service Provider Basics.
  • Have its transport provider DLL expose to MAPI its XPProviderInit initialization function.
  • Expose to MAPI its implementation of the IXPProvider and IXPLogon interfaces.
  • Expose to MAPI and client applications its implementation of the IMAPIStatus interface. For information about implementing IMAPIStatus, see Implementing a Status Object.
  • Implement a property sheet dialog box for configuration. For information about implementing property sheets, see Implementing a Property Sheet.


Working with MAPI and Other Providers

MAPI service providers of any kind must follow certain guidelines to work with other MAPI components. Each service provider must:

  • Use the proper provider and logon objects for initialization.
  • Return a dispatch table of provider entry points to the messaging system upon initialization.
  • Register a MAPI status table row for each resource owned by the provider and call the IMAPISupport::ModifyStatusRow method at appropriate times.
  • Use the IMAPISupport::NewUID method to obtain valid unique identifiers (UIDs).
  • Support the common MAPI interfaces on objects it returns.
  • Use the MAPI memory allocation functions to allocate memory returned to client applications and to release memory allocated by other parts of the MAPI subsystem.
  • Maintain a profile section, if necessary, to store credentials to the underlying messaging system.
  • Use the IMAPISupport::RegisterPreprocessor method to register any message preprocessing functions.
  • Include the proper header files (including MAPISPI.H) that define common constants, structures, interfaces, and return values.
  • Follow address format conventions for common address types.


Interacting with the MAPI Spooler

The methods in the IXPLogon interface are used by the MAPI spooler when calling the transport provider. It should be possible for most types of transport providers to implement most of these methods so that they return quickly. This is desirable because if a method takes a long time to return then it should be broken up with calls back to the MAPI spooler to release the CPU for other tasks. This is critical in nonpreemptive multitasking environments like 16-bit Windows. Transport providers for 16-bit Windows platforms should take particular care to break up any operation that takes more than 0.2 seconds. This is also necessary in 32-bit Windows to provide time to handle system-wide messages such as shutdown notifications or plug-and-play device notifications.

The MAPI spooler does its work and makes its calls to transport providers when foreground applications are idle. After possibly displaying dialog boxes when the transport provider is first logged on (governed by flags passed from MAPI to the transport provider), transport providers operate in the background unless called by the client to flush send and receive queues. When flushing queues is the only time that a transport provider need not release the CPU, and then only if the user is informed that a potentially long action is in progress. The MAPI spooler typically requests that a transport provider flush its queues in response to a user action, so the transport provider typically does not need to do anything to ensure that the user is informed.

A transport provider can independently decide to flush a queue and use the STATUS_INBOUND_FLUSH and STATUS_OUTBOUND_FLUSH bits in the PR_STATUS_CODE property of its status row to inform the MAPI spooler that it wants an inordinate amount of attention so that it can get the job done. The status row is updated using the IMAPISupport::ModifyStatusRow method. In this case the transport provider should probably display a progress indicator or other interface to inform the user that a long action is occuring.

Since network activity often takes more than 0.2 seconds, transport providers should, whenever possible, use asynchronous network requests. This enables them to initiate a request, release the CPU by calling back to the MAPI spooler, and when the MAPI spooler again gives them control, to check to see if their network request has completed. If it has not yet completed, they again release the CPU by calling back to the MAPI spooler with the IMAPISupport::SpoolerYield method.

During message processing, between IXPLogon::SubmitMessage and IXPLogon::EndMessage and during IXPLogon::StartMessage the transport provider typically makes many calls on objects exposed to it by the MAPI spooler. As part of its handling of these objects, the MAPI spooler helps the transport provider behave appropriately as a background process by yielding on its own when appropriate. A transport provider requiring time-critical processing can declare a critical section to the MAPI spooler using the IMAPISupport::SpoolerNotify support object method. In this case, the CPU is released only on explicit SpoolerYield calls by the transport provider until the transport provider ends critical section processing with another call to SpoolerNotify. Note that this is not the same as a Win32 critical section. This should only be done when the transport provider needs real-time control of external resources such as reading incoming data from a FAX line. Since this raises the priority of the MAPI spooler process and can cause the workstation to be unresponsive for the duration of the operation, it is a good idea to notify the user that a potentially long action is underway and provide a progress indicator if possible.


Initializing the Transport Provider

The transport-spooler interface defines calls the MAPI spooler makes to a transport provider. Transport providers implement these routines in a DLL. The first direct entry point in the DLL used by the MAPI spooler must be the transport provider initialization function XPProviderInit.

MAPI uses the operating system routine GetProcAddress to get the address of the provider's initialization routine and then calls that routine. The name of the initialization routine is XPProviderInit for transport providers. It is different for other types of MAPI service providers so that one DLL can contain any combination of provider types, but only one provider of a particular type. However, one provider of a given type can implement multiple services of its type. For example, one transport provider can implement message transport functionality to multiple message services.

The MAPISPI.H header file has a type definition for the function prototype of the transport provider initialization function, and a predefined procedure name for it. By naming the initialization routines in your C and C++ files with the same names used by GetProcAddress and by using a straightforward export declaration in your DLL.DEF file, you automatically get type checking of the parameters on your initialization routine. See the sample transport provider source code for examples. For more information about this sample, see Sample Transport Provider.

If a provider's initialization call succeeds but returns a service provider interface version number too small for MAPI to handle, MAPI immediately calls the Release method of the provider object and proceeds as if the initialization call had failed with MAPI_E_VERSION. This way MAPI and the provider jointly define the range of service provider interface version numbers they can handle, and if nothing matches then provider loading fails with a MAPI_E_VERSION return value.

The last step for the MAPI spooler in getting access to service provider resources is to log on to the transport provider. The MAPI spooler calls the IXPProvider::TransportLogon method of the IXPProvider object returned from XPProviderInit. This is the call where credentials, if used, are checked and dialog boxes can be allowed.

If a process opens a second transport session on the same transport provider and MAPI session, the transport provider DLL should not create a second provider object. The first provider object should be used to log on to the second transport session. A transport provider should be programmed to support multiple transport sessions in a single provider object. A second provider object should only be created if different MAPI sessions are used in the same process.


Releasing the Transport Provider

When MAPI or the MAPI spooler finishes using a transport logon object
  1. MAPI or the MAPI spooler calls the transport provider's IXPLogon::TransportLogoff method.
  2. The transport provider invalidates the status object by calling the IMAPISupport::MakeInvalid method. Whether the transport provider invalidates message objects that are being sent or received at the time of the TransportLogoff call depends on the flags that were passed to TransportLogoff.
  3. The transport provider calls the support object's Release method to remove the provider's row from the status table and remove from internal tables any Unique Identifiers (UIDs) that were set with the IMAPISupport::SetProviderUID method. It decrements the count of known logon objects active on this provider object. If the count reaches zero, MAPI calls the IXPProvider::Shutdown method and Release on the provider object. If this was the last known provider object using this DLL on this process, MAPI calls FreeLibrary on the DLL at some later time. Memory for the MAPI support object is freed and the support object Release method returns.
  4. The TransportLogoff method returns S_OK.
  5. MAPI or the MAPI spooler calls Release on the transport provider's logon object. The memory for the object is discarded.
  6. MAPI or the MAPI spooler calls FreeLibrary on the provider DLL.

For robustness, the logon and provider objects should be able to handle final Release calls on themselves without first having their TransportLogoff or Shutdown methods called. If Release is called in such cases, transport providers should treat the calls as if TransportLogoff or Shutdown had been called with a zero argument followed by Release.


Implementing the FlushQueues Method

The MAPI spooler uses the IXPLogon::FlushQueues method to download and upload any pending messages to and from a transport provider. Typically, the MAPI spooler will flush the queues for all transport providers that are logged on to the session, starting with the first transport provider as set in the transport order section of the user's profile. Flushing queues is almost always the result of a direct request by the user, so the sending and receiving of messages while queues are flushing is synchronous to the MAPI spooler. Because these calls are synchronous, the transport provider should process them as quickly as possible.

Transport providers must handle the FlushQueues call as described in the following sequence of steps to enable proper message processing and to enable external resources such as modems to be used by other transport providers as part of the MAPI spooler's FlushQueues operation.

Step | Component | Implementation
1. | MAPI spooler | Calls the IXPLogon::FlushQueues method for the first transport provider listed in the transport order of the user's profile, passing the requested flags in the ulFlags parameter. FlushQueues is called once with all flags set for the entire upload and download operation.
2. Transport Provider Needs to do a number of things before returning from the FlushQueues call.
If previously submitted messages are being deferred, the IMAPISupport::SpoolerNotify method should be called with the NOTIFY_SENT_DEFERRED flag set. Note that it is possible for the MAPI spooler to cancel a message that has been deferred before the transport provider has a chance to finish processing the message.

If the transport provider uses an external resource such as a modem, the connection to the external resource should be established.

The STATUS_OUTBOUND_FLUSH bit in the PR_STATUS_CODE property of the transport provider's status row must be set using the IMAPISupport::ModifyStatusRow method.

The transport provider should then return S_OK for the FlushQueues call.
3. | MAPI spooler | Checks the transport provider's status row for the STATUS_OUTBOUND_FLUSH bit and calls IXPLogon::SubmitMessage for the first message in the queue.
4. | Transport provider | Handles the message and returns from the SubmitMessage call.
5. MAPI spooler If the transport provider returns S_OK from SubmitMessage, the MAPI spooler calls IXPLogon::EndMessage for the message as it does with regular message sending.

If the transport provider returns a value other than S_OK from SubmitMessage, the MAPI spooler handles the value appropriately before calling EndMessage, or before calling SubmitMessage again.
6. | Transport provider | Returns from EndMessage with its message processing status in the lpulFlags parameter.
7. | MAPI spooler and transport provider | The SubmitMessage-EndMessage loop continues until all messages in the queue have been downloaded.
8. | MAPI spooler | Notifies the transport provider that it has finished downloading messages by calling the transport provider's IXPLogon::TransportNotify method with the NOTIFY_END_OUTBOUND_FLUSH flag set.
9. Transport provider Frees any external resources used in sending outbound messages so they can be used by other transport providers to flush their queues.

The STATUS_INBOUND_FLUSH bit in the PR_STATUS_CODE property of the transport provider's status row must be set using ModifyStatusRow.
10. | MAPI spooler | Checks the transport provider's status row for the STATUS_INBOUND_FLUSH bit and calls IXPLogon::StartMessage if it is set.
11. Transport provider Processes the message and returns from StartMessage. If the transport provider has other messages to upload, it should call SpoolerNotify with the NOTIFY_NEWMAIL flag set.

If the transport provider has no messages to upload, it should call IMAPIProp::SaveChanges on the message the MAPI spooler passed in StartMessage and return.

12. | MAPI spooler | Continues calling StartMessage until SaveChanges is called on a message. After the transport provider has finished uploading, the MAPI spooler calls TransportNotify with the NOTIFY_END_INBOUND_FLUSH flag set.
13. | Transport provider | Clears the STATUS_INBOUND_FLUSH bit in the PR_STATUS_CODE property of its status row using ModifyStatusRow and releases all external resources that have been released so they are available for use by other transport providers.
14. | MAPI spooler | Calls FlushQueues for the next transport provider listed in the transport order of the user's profile.

If a client application calls IMAPIStatus::FlushQueues on a transport provider's status object, the transport provider should set the appropriate bit in its status row with ModifyStatusRow. The MAPI spooler then calls the provider's IXPLogon::FlushQueues method at the MAPI spooler's convenience. When the provider's IXPLogon::FlushQueues method is called as a result of a client application's IMAPIStatus::FlushQueues call, the operation occurs asynchronously to the client application. Otherwise IXPLogon::FlushQueues works synchronously with the MAPI spooler.

For performance reasons, the MAPI spooler will only call a transport provider's FlushQueues method if the STATUS_INBOUND_FLUSH and STATUS_OUTBOUND_FLUSH flags are set in the transport provider's status row. Consequently, a transport provider can stop the FlushQueues operation at any time by clearing the STATUS_OUTBOUND_FLUSH and STATUS_INBOUND_FLUSH flags in its status row. If the MAPI spooler is shutting down and needs to end the FlushQueues operation, it calls TransportNotify with both the NOTIFY_END_INBOUND_FLUSH and NOTIFY_END_OUTBOUND_FLUSH flags set. The transport provider should release all external resources and return.


Setting Properties on Incoming Messages

The client applications within the MAPI subsystem expect a number of properties in any received message. When the transport provider brings a message into MAPI, it should set these properties, since it is either the only process with the necessary information to do so, or is at least the best source of the information.

Providers are encouraged to set the values for all of these properties in incoming messages.

Property Name | Description
PR_SUBJECT | Subject of the message.
PR_BODY | Plain text message text.
PR_RTF_COMPRESSED | Compressed RTF message text.
PR_MESSAGE_DELIVERY_TIME | Date and time the message was delivered.
PR_SENDER_NAME | Display name of the message originator.
PR_SENDER_ENTRYID | Address book entry of the message originator.
PR_SENDER_SEARCH_KEY | Address book search key of the message originator.
PR_CLIENT_SUBMIT_TIME | The time that the message was submitted to its messaging system by the sender's messaging client.
PR_SENT_REPRESENTING_NAME | Name of the representative delegate for sending.
PR_SENT_REPRESENTING_ENTRYID | Address book entry of the sending delegate.
PR_SENT_REPRESENTING_SEARCH_KEY | Address book search key of the sending delegate.
PR_RCVD_REPRESENTING_NAME | Name of the representative delegate for receiving.
PR_RCVD_REPRESENTING_ENTRYID | Address book entry of the receiving delegate.
PR_RCVD_REPRESENTING_SEARCH_KEY | Address book search key of the receiving delegate.
PR_REPLY_RECIPIENT_NAMES | List of delegated recipient display names, separated by a semicolon and space "; ".
PR_REPLY_RECIPIENT_ENTRIES | List of delegated recipients for a reply.
PR_MESSAGE_TO_ME | Indicates that the recipient was specifically named as a To recipient (not in a group).
PR_MESSAGE_CC_ME | Indicates that the recipient was specifically named as a Cc recipient (not in a group).
PR_MESSAGE_RECIP_ME | Indicates that the recipient was specifically named as a To, Cc or Bcc recipient (not in a group).

Providers which have no apparent mappings can set the PR_SENT_REPRESENTING group of properties to the same values as the PR_SENDER group, the PR_RCVD_REPRESENTING group to the same values as the PR_RECEIVED_BY group, and build the PR_REPLY_RECIPIENT group of properties based on the values of the PR_SENDER group. For example, PR_SENT_REPRESENTING_NAME can be set to the same value as PR_SENDER_NAME.

The PR_ENTRYID or PR_ENTRYLIST properties can be generated if necessary by calling the IMAPISupport::CreateOneOff method. The PR_SEARCH_KEY properties can be generated by concatenating the PR_ADDRTYPE property associated with a user, a colon ':', and the PR_EMAIL_ADDRESS property associated with the user, then folding the result to uppercase. The Windows API CharUpperBuff is a convenient function to use for this purpose. What is required of this process is to make a canonical form of the address that can be compared as a binary quantity. Note that this is not necessary if the transport provider is case-sensitive with respect to e-mail addresses.


Optional Features Transport Providers Can Implement

Optional features transport providers can implement include:

  • Registering message and recipient options specific to the transport provider.
  • Maintaining a profile, if necessary, to store configuration information and credentials to the messaging system.
  • Performing any verification of credentials required by the messaging system.
  • Supporting event notification for interested client applications with the IMAPISupport::Notify method.
  • Displaying configuration property sheets and wizard dialog boxes to enable users to configure the transport provider's settings.
  • Providing message delivery reports to client applications.


Implementing Message and Recipient Options with Transport Providers

When the MAPI spooler logs on to a transport provider, it calls the transport object's IXPLogon::RegisterOptions method. This gives the transport provider a chance to inform the MAPI spooler about any message or recipient options it supports.

MAPI client applications call one or more special callback functions you define in a DLL (probably in the same DLL as your transport provider) to handle any message or recipient options defined in your transport provider at the time messages are composed or submitted. The transport provider's RegisterOptions method defines and returns some arbitrary data to MAPI; this data is passed to the callback functions later when the client calls the IMAPISession::MessageOptions method. Your transport provider can use this data to indicate to the callback what sort of option is being processed.

The transport provider's RegisterOptions method should return an array of OPTIONDATA structures describing the options supported by the transport provider. Each structure should describe one option.

Depending on how your transport provider uses the lpszDLLName and ulOrdinal members of the OPTIONDATA structure, you can implement your callbacks as one function which handles all options (and makes use of lpbOptionsData) or as many functions which handle one option each (and probably do not use lpbOptionsData).

For more information, see IXPLogon::RegisterOptions, OPTIONCALLBACK, and OPTIONDATA.


Implementing Security with Transport Providers

If the messaging system requires it, the transport provider is responsible for implementing an appropriate level of security for access to the messaging system. Each incoming or outgoing message sent through a transport provider by the MAPI spooler is handled in the context of a provider logon session. The transport provider can display a logon dialog box to the user that prompts for a user's credentials before establishing such a connection. Alternatively, the transport provider can store the user's previously entered credentials in the secure property range within a profile section and use them for access without prompting.

When implementing your transport provider's security, consider the following:

  • With multiple installed service providers, there can be a multitude of names and passwords associated with a user.
  • MAPI allows multiple sessions with multiple identities. Providers are encouraged to support multiple sessions but are not required to do so.
  • Each session with a transport provider is associated by MAPI with a discrete section in the user's profile. The transport provider can use the IMAPISupport::OpenProfileSection method to gain access to this section, which can be used to store any information associated with this session, including credentials.
  • With multiple installed transport providers, it is not necessarily true that the user only has a single e-mail address. A user can have a separate e-mail address for each installed transport provider, or a different address for each session on a single provider.

For more information on storing credentials in profile sections, see Message Services and Profiles, and the IProfSect : IMAPIProp interface.


Displaying Configuration Property Sheets with Transport Providers

Transport providers use the IMAPISupport::DoConfigPropSheet method to implement configuration property sheets. When calling DoConfigPropSheet, the transport provider passes in a pointer to an array of properties along with information about how to display them. MAPI then presents the properties to the user by means of a standard dialog box. You are strongly encouraged to use this property sheet mechanism when implementing your transport provider due to the benefit to the user of a consistent interface.

Transport providers can use the BuildDisplayTable function to simplify construction of a display table for use with DoConfigPropSheet. Transport providers targeted at the Win32 platform only can also use the property sheet API directly. To buffer changes to the properties, transport providers can use the CreateIProp function. This simplifies the handling of cancellations by the user while the user modifies the values stored in the properties. If necessary, a transport provider can also provide a wizard dialog box to simplify configuration tasks for the user.


Sending Message Delivery Reports with Transport Providers

Some underlying messaging systems support delivery reports and some do not. How the transport provider determines whether message delivery or nondelivery reports can be sent to client applications is an implementation detail specific to individual transport providers. If delivery reports can be sent to client applications, transport providers use the IMAPISupport::StatusRecips method to notify MAPI of successful or unsuccessful delivery for one or more recipients. MAPI then generates delivery or nondelivery reports corresponding to those recipients. Transport providers can also translate incoming delivery and nondelivery reports that are native to the messaging system into MAPI delivery and nondelivery reports by means of StatusRecips.


Developing a TNEF-Enabled Transport Provider

To promote interoperability between messaging systems that support different sets of MAPI features, MAPI provides the Transport Neutral Encapsulation Format (TNEF) as a standard way to transfer data. This format encapsulates MAPI properties not supported by an underlying messaging system into a binary stream that can be transferred along with the message when a transport provider sends it. The transport provider that receives the message can then decode the binary stream to retrieve all the properties of the original message and make them available to client applications. The operational model for TNEF is:

  • Messaging clients submit and receive messages to a TNEF transport as normal.
  • The transport separates the properties on outgoing messages into two categories: those that the underlying message system supports and those that it doesn't. The values of the properties that are supported by the underlying messaging system are translated into the required format.
  • The transport uses the MAPI TNEF methods to encode any unsupported properties into a single data stream. The transport then turns that data stream into a special attachment on the outgoing message, using the underlying messaging system's attachment model, before sending the message.
  • A TNEF enabled transport that receives such a message does two things. First, it translates the incoming message's properties — the ones supported by the underlying message system — into MAPI properties. Second, if the special attachment is present, it uses the MAPI TNEF methods to retrieve additional MAPI properties from the attachment before delivering the message to a client application.

MAPI supplies an implementation of the ITnef interface for use by MAPI transport providers when working with TNEF objects. The OpenTnefStreamEx function is used to create TNEF objects and associate them with a message. TNEF streams are built on top of the OLE IStream interface. For more information on OLE and the IStream interface, see the COM and ActiveX Object Services section in the Platform SDK.

Note You use OpenTnefStreamEx to create TNEF objects. The old OpenTnefStream function still exists for compatibility with old source code and should not be used in anything new.

The ITnef interface provides the following methods:

AddProps

EncodeRecips

ExtractProps

Finish

FinishComponent

OpenTaggedBody

SetProps

The MAPI TNEF implementation model supports:

  • All MAPI properties without affecting other message properties.

    In order for MAPI messages to survive transport through a messaging system, all properties that cannot be encoded as properties of the messaging system must be encapsulated. Because it is almost never known at the time a message is sent whether or not a MAPI-compliant client will receive the message, the encapsulation scheme allows a transport provider to encode only those MAPI message properties that the messaging system does not natively support. This means that messages which use TNEF are not "opaque" to messaging systems that are not based on MAPI such as SMTP-based UNIX messaging systems. These systems receive the properties they support in whatever manner is typical for them, and other properties are received as an encoded TNEF data stream. The TNEF transport provider is responsible for differentiating between these two sets of properties and sending the supported set in the proper manner for the messaging system.

    TNEF makes no assumptions as to the level of support provided by a messaging system. However, in the examples of TNEF usage included in this section, the assumption is made that the messaging system supports at least one single attachment aside from the message. In some cases, the attachment can only be supported through a uuencoded stream and transmitted as part of the message text. Only in very rare circumstances will the messaging system have so little support for message properties that full TNEF encoding of all properties is necessary.

  • Workgroup Mail encapsulations.

    The Mail Client for Windows for Workgroups Version 3.1 implements a minimal TNEF encapsulation of some special properties. The MAPI TNEF scheme and underlying formats are backward compatible with this encapsulation mechanism.

  • A mechanism for determining whether a TNEF stream on an incoming message belongs to the message based on the MAPI property PR_TNEF_CORRELATION_KEY.

    This property should be found both in the TNEF stream and in an appropriate message header. If the property has the same value in both places, or is missing in either place, the TNEF stream is assumed to belong to the message. Otherwise, the TNEF stream is ignored. TNEF enabled transports are responsible for choosing a value for this property on outbound messages and encoding it in an appropriate message header (for example, the Message-ID: header for SMTP messages) and in the TNEF stream.


TNEF Processing

The following series of actions describe how transports use TNEF methods to process outgoing and incoming messages.

To send a message that includes a TNEF stream
  1. Process the message properties that are supported by the messaging system.
  2. Mark the message in an implementation specific way so that the receiving transport provider can determine that the message requires TNEF processing. For example, a TNEF transport provider sending to an SMTP messaging system might add a custom header field like "X-CONTAINS-TNEF" to indicate that the message contains TNEF data.
  3. Obtain a TNEF object and uses it to encapsulate the message properties not supported by the messaging system into a TNEF stream.
  4. Encode the TNEF stream using the messaging system's attachment model. For example, if the underlying attachment model is to uuencode attachments and append them to the message text, then the transport provider must uuencode the TNEF stream into another attachment.

    The transport provider must also implement a method for recognizing which attachment contains the encoded TNEF stream when it receives a message. The standard way to mark this attachment is to give it an attachment filename of "WINMAIL.DAT". If your transport provider does this, any other TNEF-enabled transport providers that follow this convention will be able to interoperate with it.

  5. Use ITnef interface methods to insert tags describing the positions of message attachments in the message text.
  6. Access the tagged message text through OLE IStream methods, and send it to the messaging system.
To retrieve encapsulated properties
  1. Write the properties supported by the messaging system into a new message, including the tagged message text that contains the encapsulated properties.
  2. Decode the TNEF stream from the proper attachment.
  3. Decode any other attachments and write them to new MAPI attachments on a message.
  4. Open the TNEF stream for decoding using the OpenTnefStreamEx function.
  5. Use the ITnef::ExtractProps method to decode the TNEF stream and write the encapsulated properties into the new message. Any encoded properties that are duplicates of nonencoded properties will overwrite them when the encoded properties are decoded.
  6. Use the ITnef::OpenTaggedBody method to parse the message text to recover attachment positions from the tags in the message text.


Encoding a Message with TNEF

When a message is submitted, the transport provider can create a file that is used to contain the message during transmission. Next, an OLE IStream interface is wrapped around the file. The transport provider then uses ITnef methods to write the message properties to the stream in a tagged format that enables the properties to be easily decoded by the receiving transport providers.

To represent an entire message in a single file
  1. Obtain a TNEF object by passing an IStream object and a message into the OpenTnefStreamEx function.
  2. Get a list of all defined properties for the message by calling the IMAPIProp::GetPropList method.
  3. Use IMAPIProp methods to exclude all properties supported by the messaging system. At an appropriate time write those properties to the messaging system in the format required by the messaging system.
  4. Call ITnef::AddProps to encode the remaining properties, including all attachments.
  5. Call the ITnef::Finish method to encode the message into the TNEF stream after all the requested properties are added.
  6. Call the ITnef::OpenTaggedBody method to obtain the tagged message text. This tagged text is written out to the messaging system using methods from the OLE IStream interface.
  7. Call the IUnknown::Release method to release the ITnef object.
To process an inbound TNEF message
  1. Get a MAPI message object from the MAPI spooler and write message header properties into the new MAPI message.
  2. Create and initialize an IStream object to contain the TNEF data from the inbound message.
  3. Pass the MAPI message and the IStream object to the OpenTnefStreamEx function.
  4. Decode the information in the TNEF data by calling the ITnef::ExtractProps method. It is important to note that anything decoded by ExtractProps will overwrite properties decoded from the incoming message's envelope. That is, extracted TNEF properties will overwrite the existing properties in a message.
  5. Process the tagged message text by calling ITnef::OpenTaggedBody and the text is parsed to recover attachment positions.
  6. Save the message by calling IMAPIProp::SaveChanges.
  7. Release the TNEF object by calling the IUnknown::Release method.


Custom Processing with TNEF

Transport providers can use custom processing to process the properties on an attachment itself, transmit attachments separately, or transmit them through the messaging system's attachment model. TNEF uses a mechanism that enables the transport provider to send the attachments apart from the message and reconnect them on the receiving side.


Sending Messages with TNEF Custom Attachment Processing

To customize attachment processing when sending a message
  1. Obtain a TNEF object by passing an IStream object and a message into the OpenTnefStreamEx function.
  2. Get a list of all defined properties for the message by calling the IMAPIProp::GetPropList method.
  3. Use IMAPIProp methods to exclude all properties supported by the messaging system. At an appropriate time write those properties to the messaging system in the format required by the messaging system.
  4. Call the ITnef::AddProps method to add only the properties on the message — that is, none of the properties on the attachments — by setting the TNEF_PROP_MESSAGE_ONLY flag.
  5. Call ITnef::AddProps with these items: the TNEF_PROP_EXCLUDE flag, a property tag array that contains the PR_ATTACH_DATA_BIN or PR_ATTACH_DATA_OBJ property, and an attachment identifier that specifies the attachment to be processed.
  6. Use the ITnef::SetProps method to add the PR_ATTACH_TRANSPORT_NAME property tag with a unique string that identifies the attachment to the messaging system if the attachment has a filename that the messaging system cannot support. For example, multiple attachments with the same original filename, or a filename that is not a valid filename for the messaging system. This string will be used with a key number when writing the attachment tags in the tagged message text to associate an attachment with its data. See, TNEF Tagged Message Text.
  7. Repeat the AddProps and SetProps calls for each attachment.
  8. Call the ITnef::Finish method to encode the message into the TNEF stream after all the requested properties are added.
  9. Obtain the tagged message text by calling the ITnef::OpenTaggedBody method. This tagged text is read using methods from the IStream interface, encoded using the messaging system's attachment model, and written out to the messaging system.
  10. Call the IUnknown::Release method to release the ITnef object.
  11. Write the remaining attachments to the messaging system through the messaging system's attachment model.

It is highly recommended that your transport provider use the method just described to process attachments. If that is not possible, a second method for customized attachment processing is available:

The transport provider ensures that the PR_ATTACH_TRANSPORT_NAME properties of all the attachments contain unique values that are valid attachment identifiers for the messaging system. The transport provider then uses a single call to ITnef::AddProps for each attachment, passing in the TNEF_PROP_CONTAINED flag.


Receiving Messages with TNEF Custom Attachment Processing

To receive a TNEF message with customized attachment processing
  1. Import all the transmittable properties — those that the messaging system supports — from the incoming message into a new MAPI message. This includes the message text, which contains the TNEF data stream.
  2. Identify and decode the special attachment that contains the TNEF stream.
  3. Extract all the attachments from the incoming message into MAPI attachments on the new MAPI message. The recovered filenames, or other identifying markers on the attachments, should be placed into the PR_ATTACH_TRANSPORT_NAME property of the new attachments so that the ExtractProps method can later associate the correct attachment with the attachment tags encoded in the message text.
  4. Create an OLE IStream object to wrap around the decoded TNEF stream and use that object along with the new MAPI message in a call to the OpenTnefStreamEx function.
  5. Call the ITnef::ExtractProps method to recover the nontransmittable properties on the message from the TNEF data stream.
  6. Call the ITnef::OpenTaggedBody method with the MAPI_CREATE and MAPI_MODIFY flags set. This call removes the attachment tags from the message text and converts them into attachment position information in the MAPI message.
  7. Deliver the message through the MAPI spooler.


TNEF Tagged Message Text

Tagged message text is used by TNEF to resolve attachment positions in the parent message. This is done by adding a place holder in the message text at the position of the attachment. This place holder, or attachment tag, describes the attachment in such a way that TNEF knows how to resolve the attachment and its position. The tags are formatted as follows:

[[ <Object Title> : <KeyNum> in <Stream Name> ]]
[[ <File Name> : <KeyNum> in <Transport Name> ]]

The <Object Title> and <File Name> are variables containing values that are taken from the attachment itself. In cases where these values are not available, the title is defaulted by TNEF based on the attachment type.

The <KeyNum> variable contains the textual representation of the attachment key assigned to the attachment by TNEF. The base value of the key is passed into the OpenTnefStreamEx call. The base value must not be zero and should not be the same for every call to OpenTnefStreamEx. It should suffice to use pseudo random numbers based on the system time from whatever random number generator your run-time library provides, as long as you guarantee that they are never zero.

The <Transport Name> variable contains either the stream name passed into the OpenTnefStreamEx call or the value of the PR_ATTACH_TRANSPORT_NAME property.

Note The PR_ATTACH_TRANSPORT_NAME property and the <Transport Name> variable in a message text tag have nothing to do with the name of the transport provider you are implementing. These items represent the name of an attachment for the transport provider and messaging system.

The message text is tagged when a transport provider asks for a tagged message text by calling the ITnef::OpenTaggedBody method. When reading from the tagged text stream, TNEF replaces the single character that was in the message text at the index provided in the PR_RENDERING_POSITION property with the appropriate tag. When writing to the tagged text stream, TNEF checks the incoming data for tags, finds the associated attachment, and replaces the tag with a single space character.

Note that by using tagged message text, a transport provider can preserve the positioning of attachments regardless of most changes made to the message text by messaging systems.


Encoding Recipient Tables with TNEF

The encoding of a recipient table into the TNEF stream is rarely necessary since most messaging systems support recipient lists directly. In general, the recipient properties are transmitted in the message header. When inclusion of the recipient table is necessary, TNEF can encode the recipient table as a part of its usual processing. This is done during the initial phase of TNEF processing. The transport provider can include the message's recipient table by calling the ITnef::AddProps method with the PR_MESSAGE_RECIPIENTS property specified in the inclusion list. TNEF gets the recipient table from the message, queries the column set, and processes every row of the table into the TNEF stream.

An alternate method is available if the transport provider needs to modify the recipient table before it is encoded. The transport provider can construct the necessary table and then call the ITnef::EncodeRecips method. If NULL is passed in the lpRecipTable parameter, then the recipient table is taken directly from the message as described for ITnef::AddProps.


Developing a Remote Transport Provider

Some client applications benefit from having a transport provider with remote capabilities, including:

  • Clients whose underlying messaging systems are slow.
  • Clients with low bandwidth connections to their messaging servers.
  • Clients with intermittant connections to messaging systems or networks.
  • Clients that must, for whatever reasons, minimize the time spent connected to their message servers.

The most common situation where remote transport providers are used is when a client's connection to the messaging server is over a modem (low bandwidth) or is connected through a long-distance telephone call.

MAPI provides a definition of a remote interface that transport providers implement in order to satisfy clients' needs in these circumstances. That interface is the IMAPIFolder interface, which enables a user to preview the contents of the messaging server without downloading entire messages or folders. This is the same interface that message store providers implement. By having a transport provider implement a special MAPI folder, it can provide access to messaging systems with special connection requirements.

The topics in this section describe the remote transport architecture and provide information for implementing a remote transport provider.


Remote Transport Architecture

Your remote transport needs to translate user requests for message data into intelligently managed connections to the messaging server without requiring the user to manage the individual connections. This is accomplished through the MAPI remote architecture as shown in the following illustration.

Client applications which are remote-enabled (remote viewers) communicate with the MAPI spooler and remote transport providers as usual for nonremote tasks such as logging on or flushing queues. In addition, the client application uses the remote transport's IMAPIFolder interface to perform remote tasks such as downloading message headers.

The remote viewer is a client application designed to work with remote transport providers. Remote viewer applications can check the MAPI status table for remote transport providers, those that have set the STATUS_REMOTE_ACCESS bit in their status table row, and adjust their user interface appropriately. Remote viewers are expected to utilize a special folder that contains header information about messages in the user's Inbox. The header information is stored locally and can be used to selectively mark messages for download or deletion.

A remote transport provider is similar to a message store because it implements the IMAPIFolder interface; however, the folder so implemented is not identical to the generalized hierarchical folders that message stores implement. For a remote transport provider, the folder is an intermediary between the client application and the remotely accessed message store. The message headers and message identifiers in the folder do not necessarily correspond to messages that are stored locally on the user's computer or stored in any immediately accessible way.

The folder is expected not to have subfolders, although the presence of subfolders should not cause client application problems since they should not be displayed. Opening the folder does not cause the folder's contents to be downloaded. At the user's request, message headers can be downloaded and looked at off-line or at a later time. Remote transport providers should provide some sort of local cache or storage facility for downloaded message headers so that the folder can be populated with cached message headers when it is opened without connecting to the remote message store.


Advertising a Remote Transport

Remote viewer applications need a way to identify which transport providers support remote functionality. In order to advertise this ability to remote viewers, remote transport providers must set the STATUS_REMOTE_ACCESS bit in the PR_STATUS_CODE property and the STATUS_VALIDATE_STATE bit set in the PR_RESOURCE_METHODS property of the transport provider's row in the status table.

Remote transport providers must also include in the status row the PR_HEADER_FOLDER_ENTRYID property. This property indicates the entry identifier of the folder that is used for downloading by remote viewer applications. This entry identifier is registered with MAPI when the transport provider is initialized. When the user opens the folder, the remote viewer application calls the IMAPISession::OpenEntry method passing in the folder's entry identifier. MAPI then forwards the call to the transport provider which registered the folder's entry identifier. The transport should return a view of the contents of the folder. This folder's contents table should contain the list of messages in the folder.


Required Status Row Properties for Remote Transports

Remote transport providers must supply the following properties when their initial row in the MAPI status table is created:

PR_DISPLAY_NAME

PR_HEADER_FOLDER_ENTRYID

PR_REMOTE_PROGRESS

PR_REMOTE_VALIDATE_OK

PR_RESOURCE_METHODS

PR_RESOURCE_PATH

PR_PROVIDER_DISPLAY

PR_STATUS_CODE

PR_STATUS_STRING


Additional Remote Transport Functionality

To support as many remote viewer requests as possible, your remote transport provider should be able to:

  • Defer message delivery.
  • Dynamically update the PR_REMOTE_PROGRESS and PR_REMOTE_PROGRESS_TEXT properties while a remote operation is in progress.
  • Support the PR_REMOTE_VALIDATE_OK property.


Implementing Folders for Remote Transports

Since the folder that remote transport providers implement is not a fully functional MAPI folder, remote transport providers do not have to implement all the methods in the IMAPIFolder interface. You do need to implement the IMAPIFolder::SetMessageStatus method. You should derive a C++ class from the IMAPIFolder interface to implement the folder. Because IMAPIFolder inherits from the IMAPIContainer, IMAPIProp, and IUnknown interfaces, there are some methods from those interfaces that need to be implemented as well. Methods from those interfaces that are not listed here should be implemented as stubs which return MAPI_E_NO_SUPPORT.

IMAPIFolder is a pure virtual interface, containing no data members or predefined methods, only method declarations. You must implement basic functionality such as a constructor and destructor, reference counting, and declaring and defining any needed member variables. Your class's declaration should include data members for the folder's contents table, a pointer to the logon object and status object (the parent objects of the folder), and a reference counter.

Since the IMAPIFolder interface itself does not define any mechanism for filling the contents table with message headers, you will need to define custom methods to do this. The minimum implementation of this interface has read-only functionality. You will need to implement additional methods to give your implementation read/write functionality.

The only method from the IMAPIContainer interface that must be fully implemented is GetContentsTable. The remaining methods can return MAPI_E_NO_SUPPORT.

Remote transport providers must implement only four methods from the IMAPIProp interface in addition to the usual stubs for the other methods in this interface. The required IMAPIProp methods are:

GetLastError

SaveChanges

GetProps

GetPropList

Because MAPI adheres to the OLE component object model, you must implement a few methods from IUnknown.

The semantics of the QueryInterface method that your implementation should follow are described in the Platform SDK. If the interface identifier passed into QueryInterface is one of IID_IMAPIFolder, IID_IMAPIContainer, or IID_IMAPIProp, then a pointer to the folder object should be passed back to the caller in the parameter provided for that purpose, the reference count of the folder must be incremented, and the method should return S_OK.

If the interface identifier passed in is IID_IUnknown, then a pointer to the transport provider's status object should be returned, according to the OLE common object model (COM) rules, and the status object's AddRef method should be called before QueryInterface returns S_OK.

If the interface identifier is anything else, QueryInterface should return MAPI_E_INTERFACE_NOT_SUPPORTED.

Your implementation of IUnknown::Release should do the following things:

  • Decrement the reference count for the folder.
  • If there are no remaining external references to the object — that is, the folder object contains its only remaining reference — and the transport provider caches the folder's contents table, this is the time to save the contents table to whatever external resource is appropriate.
  • If the reference count is zero, the folder should delete itself.


Implementing the Folder Constructor

The remote transport provider's IMAPIStatus object will call the folder's constructor with a pointer to the status object and a pointer to the transport provider's IXPLogon object. The constructor needs to perform the following MAPI-specific tasks:

  • Store the status object pointer and logon object pointer in data members.
  • Call the AddRef methods on the status object and logon object.
  • Initialize the folder's contents table to NULL.
  • Initialize the folder object's reference count mechanism.

As usual, the constructor should take care of initializing any implementation-specific data members.


Implementing the Folder Destructor

The folder's destructor needs to perform the following MAPI-specific tasks:

  • If the folder still has a contents table, call the table's Release method and set the pointer to the table to NULL.
  • Call the Release method on the status object and logon object, and set the pointers to those objects to NULL.

As usual, the destructor must also free any additional memory allocated by the folder.


Implementing Status Objects for Remote Transports

You should derive a C++ class from the IMAPIStatus class to implement this interface. Because IMAPIStatus inherits from the IMAPIProp and IUnknown classes, there are some methods from those interfaces that need to be implemented as well. Methods from those interfaces that are not listed here should be implemented as stubs which return MAPI_E_NO_SUPPORT.

Remote transport providers must implement the following IMAPIStatus methods:

IMAPIStatus::ChangePassword

IMAPIStatus::FlushQueues

IMAPIStatus::SettingsDialog

IMAPIStatus::ValidateState

Since remote transport providers, like other MAPI service providers, use the MAPI status table, they must implement some methods from the IMAPIProp interface to support client requests for property information. These methods are:

IMAPIProp::GetLastError

IMAPIProp::SaveChanges

IMAPIProp::GetProps

IMAPIProp::GetPropList

The only method from the IUnknown interface that is special for MAPI is the QueryInterface method.

The semantics of the QueryInterface method that a remote transport provider's implementation should follow are described in the Platform SDK. If the interface identifier passed in is one of IID_IMAPIStatus, IID_IMAPIProp, or IID_IUnknown, then a pointer to the status object should be passed back to the caller in the parameter provided for that purpose, and your status object's reference count must be incremented.

If the interface identifier passed in is IID_IMAPIFolder, then your implementation should return a pointer to the folder that contains the available message headers and increment the reference count for that folder. If no folder is present, one should be created and then returned.

If the interface identifier is anything else, QueryInterface should return MAPI_E_INTERFACE_NOT_SUPPORTED.


Implementing the Status Constructor

The constructor for your implementation of the IMAPIStatus interface must do the following:

  • Store the pointer to the XPLogon object passed in the first parameter to the constructor.
  • Store the pointer to the profile section object passed in the second parameter to the constructor.
  • Initialize the status object's reference count mechanism.
  • If the profile section pointer is not NULL, call the AddRef method on the profile section object.


Implementing the Status Destructor

The only thing that the destructor for your implementation of the IMAPIStatus interface must do is call the Release method on the profile section object if the profile section pointer is not NULL.


Background Processing and Allocating Scarce Resources

Transport providers operate largely at the direction of the MAPI spooler. This places remote transport providers under some obligations in order to interact with other MAPI service providers. Remote transport providers should strive to operate in the background in order not to cause client applications to appear inactive. Remote transport providers should also strive to minimize their use of scarce resources, such as modems and COM ports, in order to permit other MAPI service providers and other user applications to use those resources if necessary.


About Background Processing

Whenever possible, your transport provider should operate in the background. The transport provider's actions should be initiated by the MAPI spooler rather than directly by client calls to methods in the transport provider to avoid conflicts with other service providers (especially other transports) that might need to use resources that your transport provider also needs. Following is the typical sequence of actions:

  1. The client calls a method in the transport provider which requires some action.
  2. The transport provider sets some internal status flags which note the action requested by the client.
  3. The transport provider sets one or more special values in the MAPI status table which signal the MAPI spooler that the transport provider needs to perform the requested action.
  4. The MAPI spooler calls one or more methods in the transport provider to initiate the requested actions.


Guidelines for Allocating Scarce Resources

Transport providers that use scarce resources — such as a modem or COM port — to send and receive messages or message headers need to adhere to the following conventions in order to avoid resource conflicts with other transport providers:

  • Transport providers can allocate scarce resources when the TransportLogon method is called and retain them until the RegisterOptions method returns, at which time the resources must be released.
  • Transport providers can allocate scarce resources when the SubmitMessage method is called and retain them before returning from the subsequent call to the EndMessage method.
  • Transport providers can allocate scarce resources for the duration of a call to the StartMessage method. The transport provider must release the resources before returning.
  • Transport providers that need to keep a resource open across multiple method calls, such as while flushing queues, should signal the MAPI spooler of this need by setting the STATUS_INBOUND_ENABLED or STATUS_OUTBOUND_ENABLED bits in the transport provider's PR_STATUS_CODE property in the MAPI status table.

    When the MAPI spooler next makes a call to a method in the transport provider's logon object the transport provider can allocate the resource. The transport provider can keep the resource until the time that the action, such as flushing queues, is completed. In some cases, the transport provider will already hold the resource before calling the IMAPISupport::ModifyStatusRow method to update the transport provider's PR_STATUS_CODE property. This will cause some multi-transport operations to fail, but is sometimes unavoidable. The MAPI spooler will handle errors in such cases.


Developing a Message Store Provider

Like other MAPI service providers, message stores are dynamic-link libraries (DLLs) that present the services of some underlying storage mechanism to MAPI client applications and the MAPI spooler. The message store provider presents the underlying storage mechanism as a hierarchical set of folders and messages that MAPI clients and the MAPI spooler can use.

This diagram shows the basic MAPI message store architecture.

You can implement a message store provider using any sort of underlying storage mechanism you like. However, performance concerns and the requirement that the underlying storage mechanism must be presented as a hierarchical collection of MAPI objects means that message stores are typically implemented using an existing database product which supports hierarchical storage of objects in the database and which has a programming interface or well defined file structure. For example, Access, SQL, and Oracle databases can be used as the underlying storage mechanism. Some database products have feature sets that make it easier to implement MAPI features, so your choice of database product may be affected by the features that your message store provider needs to support.

Using an existing database as the underlying storage mechanism saves you work because it is usually easier to present database objects to MAPI clients as MAPI objects than to implement your own hierarchical storage mechanism. Doing this allows you to treat MAPI operations at a higher level than if you implement your own hierarchical storage mechanism. For example, searching for a message with a particular subject line becomes a fairly simple matter of constructing and submitting an appropriate database query rather than a matter of implementing complex routines to search your hierarchical storage mechanism.

Message store providers communicate with MAPI clients and the MAPI spooler to perform operations on folders and objects. The message store provider translates those operations into lower level operations on the underlying storage mechanism. The MAPI spooler typically communicates with the message store provider while sending and receiving messages. MAPI clients typically communicate with message store providers in order to manipulate the folder hierarchy and to read, edit, delete, and send messages.

Both the MAPI spooler and MAPI clients communicate with the message store provider to create new messages. Client applications do this when users compose a message. The MAPI spooler does this when it receives an incoming message. In either case, the new message is usually created in the Inbox folder of the message store, if there is one.

Message store providers make heavy use of MAPI tables, folders, messages, and properties. The implementation details for those objects are documented in Tables, Folders, Messages, and Properties. You should familiarize yourself with that material before attempting to implement a message store provider.

There are two important types of message store providers: those that can act as a user's default message store and those that cannot. A default message store is one in which client applications and the MAPI spooler can perform any messaging task, such as receiving messages or creating folders. A default message store provider must support several more features than the minimum number required for all message store providers.


Structure of Message Store Providers

A message store provider, when it is running in memory, is an IMSProvider : IUnknown object. The IMSProvider interface allows client applications and the MAPI spooler to log on to and off of the message store. The objects that client applications and the MAPI spooler use to access folders and messages in the message store are an IMSLogon object and an IMsgStore object. These objects are typically created when the message store is first logged on to, although the message store DLL's MSProviderInit entry point could also create them.

Because the IMSLogon and IMsgStore interfaces share some methods, it may be easier to create one class object that inherits from both of these interfaces. You can also implement these interfaces in separate objects, and write helper functions internal to your DLL that implement the shared methods which can then be called from the methods in the IMSLogon and IMsgStore interfaces.

The following illustration shows a high-level outline of the object hierarchy within a running message store.


Required and Optional Interfaces for Message Store Providers

MAPI defines a set of interfaces that relate to message store providers. Because of the wide range of features that a message store can choose to implement, some of these interfaces are required and some are not. The following table lists the MAPI interfaces related to message store providers, whether the interfaces are required or optional, and why they are used.

Interface | Status | Use
IMSProvider | Required | Logging on and off a message store.
IMSLogon | Required | Opening folders or messages, verifying the message store's identity, and handling notifications.
IMsgStore | Required | Opening folders or messages, finding special folders, handling message submissions.
IMAPIFolder | Required | Finding and manipulating messages and sub-folders.
IMessage | Required | Manipulating attachments and setting some of a message's properties.
IMAPITable | Required | Used by other objects to present collections of data to various MAPI components.
IMAPIStatus | Required | Allows clients to validate the state of a message store, and perform some configuration tasks.
IAttach | Optional | Used by message objects if the store provider supports file attachments.
IStorage | Optional | OLE interface used by attachment objects if the store provider supports OLE object attachments.
IStream | Optional | OLE interface used by message and attachment objects.
IStreamDocfile | Optional | OLE interface used by some OLE 2 attachment objects.

The basic information you need to implement IMAPIFolder, IMessage, IMAPIStatus, and IMAPITable is documented in the reference topics for these interfaces. This section contains supplementary information that is more directly related to message store providers. The rest of the MAPI interfaces should be implemented according to the information in this section and in the appropriate reference topics. See the COM and ActiveX Object Services section in the Platform SDK for details about implementing IStorage, IStream, and IStreamDocFile.


Message Store Features

Message store providers are more complex than other MAPI service providers in that message store providers have a wider range of optional features they can implement. The list of required features for a message store provider is fairly short. However, a typical message store provider will support a number of optional features, since many of the optional features are very useful or required by most MAPI clients. The following table lists the major features that message store providers can implement and whether each feature is required or optional for all message store providers and for default message store providers.

Feature | All | Default
Providing status with the MAPI status table | Required | Required
Implementing folder objects | Required | Required
Implementing message objects | Required | Required
Read and nonread reports | Required | Required
Progress interface | Required | Required
Configuration interface | Required | Required
Supporting associated contents tables for form and view support | Optional | Optional
Sending messages with the message store provider | Optional | Required
Receiving messages with the message store provider | Optional | Required
Supporting message attachments | Optional | Optional
Supporting Rich Text Format for messages | Optional | Optional
Providing notifications | Optional | Optional
Supporting searches | Optional | Optional
Tightly coupled message store/transport providers | Optional | Optional
Non-reuse of entry identifiers | Optional | Optional

Many of the optional features can be advertised to MAPI and client applications by setting various flags in the message store object's PR_STORE_SUPPORT_MASK property. The required features do not have flags associated with them. PR_STORE_SUPPORT_MASK is required on message store, folder, and message objects.


Implementing Folders in Message Stores

A great deal of the information relating to message store providers' support for folders is covered in Folders. You should be familiar with that information before attempting to implement a message store provider. The Folders section is heavily oriented to the MAPI client's perspective; this topic covers additional information that is important from the message store provider's point of view.


Exposing Folders in Message Stores

Every message store provider must present a top-level IMAPIFolder object to client applications. The top-level folder corresponds to the entire message store; it provides access to the folders that users see as the contents of the message store. In addition, the top-level folder is often used as the default receive folder for IPC messages and as the folder from which read reports are sent. Message store providers must also present an IPM subtree — a set of folders used to contain IPM messages — to client applications.

Client applications can open the top-level folder by calling IMsgStore::OpenEntry with 0 and NULL for the cbEntryId and lpEntryId parameters. In most cases, however, client applications open the set of folders containing IPM messages.

To get a list of folders in the message store's IPM folder tree
  1. Use your MAPI session to call the IMAPISession::OpenMsgStore method.
  2. Use the resulting message database pointer to call the IMAPIProp::GetProps method for the PR_IPM_SUBTREE_ENTRYID property.
  3. Call the IMsgStore::OpenEntry method with the entry identifier to get an IMAPIFolder pointer.
  4. Call the IMAPIContainer::GetHierarchyTable method to get a table of the contents of the folder.
  5. Call the IMAPITable::QueryRows method to list the folders in the top-level folder.

MAPI clients use these folders to access other folder objects and message objects in the message store. IMAPIFolder, and its parent interface IMAPIContainer, contain the methods your message store provider must implement to populate folders with message objects and respond to clients' requests to operate on messages.


Inbox and Outbox Folders in Message Stores

In order to be the default message store, a message store provider must implement an Inbox and an Outbox folder. They are typically stored within the IPM subtree of a message store. These folders are special in that they are designated as the folders that messages are delivered to and sent from, but no special functionality is required of them. Sending and receiving messages happens by way of defined call sequences between client applications, the MAPI spooler, and the message store provider. The Inbox and Outbox folders are simply folders that are used to hold messages during those call sequences. The important point is not that the folders are special, or even that they are named Inbox and Outbox; the important point is that the message store provider uses them as part of its support for sending and receiving messages.

To support receiving messages, the message store provider must implement the IMsgStore::GetReceiveFolderTable and IMsgStore::GetReceiveFolder methods. See Receiving Messages with Message Store Providers for details.

To support sending messages, the message store provider must support the IMsgStore::GetOutgoingQueue method in addition to the other methods used by the MAPI spooler during the message sending process. A message store's outgoing queue does not have to correspond to an actual folder anywhere in the message store's folder tree. However, it is customary for a message store provider to show the contents of the outgoing message queue in the Outbox folder, if there is one. Doing so gives client applications a convenient way to indicate the status of messages that the user has sent, since an Outbox folder can be displayed along with all the other folders in a message store. See Sending Messages with Message Store Providers for details.


Special Folders in Message Stores

Special folders such as the Inbox, Outbox, and search-results folder, may be pre-created and protected by the message store provider. If the folders don't exist, MAPI will attempt to create them in the message store by calling the HrValidateIPMSubtree function. For more information, see Special Folders.


Implementing Messages in Message Stores

The IMessage interface is similar to the IMAPIFolder interface in that both interfaces derive from the IMAPIProp interface. Clients use the IMAPIProp methods to access the contents of a message. The IMessage interface supplies additional methods for manipulating messages, such as for adding attachments or modifying the recipients of a message. The methods in the IMessage interface serve to modify attributes of messages that are not stored directly in the message's properties.


Creating and Storing Messages in Message Stores

How your message store provider creates and stores messages in the underlying storage mechanism depends heavily on the underlying storage mechanism itself. In general, you need only to write code to preserve the properties of a message and their values.

When creating a new message, the message store provider needs to create it with the required properties for messages. A list of these properties can be found in the documentation for IMAPIFolder : IMAPIContainer. After that, client applications add any additional properties with IMAPIProp methods.

When saving a message to the underlying storage mechanism, the message store provider needs to iterate over the message's properties, and save them to the underlying storage mechanism such that they can be fully recovered if the message is later opened.

MAPI requires that the properties on IMessage objects are transacted, meaning that changes made to them do not become permanent until the IMAPIProp::SaveChanges method is called on the message object. The message store provider is responsible for implementing this behavior. Usually this is not difficult; it simply means holding properties in memory while they are being modified and committing them to the underlying storage mechanism when SaveChanges is called.

Some properties on message objects have special semantics for client applications with respect to the SaveChanges method:

  • Some properties should be read/write before SaveChanges is called, but read-only afterwards. For example, PR_MESSAGE_FLAGS is set initially by the client application that creates the message (and thus is read/write) but can't be changed after the first call to SaveChanges.
  • Some properties have special relations to properties on the folder they are in or to IMAPIFolder methods. For example, the PR_MESSAGE_FLAGS property is related to the flags used on the IMAPIFolder::CreateMessage call.
  • Some properties may not be available until SaveChanges is called for the first time. For example, the PR_ENTRYID property may not be available until SaveChanges is called.
  • Some properties can have special relationships to other properties on the message object. For example, the PR_BODY property is usually derived from the PR_RTF_COMPRESSED property in message store providers that support Rich Text Format messages.
  • Some properties are used by more than one object type related to message stores. For example, the PR_STORE_SUPPORT_MASK property is required on folder and message objects as well as message store objects.

It is the responsibility of the message store provider to implement the correct semantics for such properties.


Supporting Named Properties in Message Stores

Message objects can have properties in them that are not in the set of properties defined by MAPI. Such properties can be unnamed or named. Unnamed properties must reside in a range of property identifiers defined by MAPI. Named custom properties reside in a different range of property identifiers defined by MAPI. They are typically used by custom message types. Your message store provider must support named properties if it is to be used as the default message store. Supporting named properties means implementing the IMAPIProp::GetNamesFromIDs and IMAPIProp::GetIDsFromNames methods, and implementing one or more mapping signatures that identify what names go with what property identifiers. For more information, see Defining New Properties and Supporting Named Properties.

Most message store providers that support named properties use a single mapping signature for all objects in the message store. This has two benefits. One is that it is simpler to implement mapping signatures if there is only one to keep track of. The second benefit is that if all objects in the message store use the same mapping signature, then client applications are assured that all property identifiers on messages in the message store actually refer to the same named property. This allows client applications to display columns for named properties in their folder view interface.


Supporting Multivalued Properties in Message Stores

The requirements for supporting multivalued properties are documented in Properties. Multivalued property support is not required for message store providers but it is recommended, particularly for default message store providers. Some other features, such as folder form libraries, do require multivalued property support.


Supporting Multiple Client Access to Messages in Message Stores

It is possible for multiple client applications to open a given message simultaneously. Message store providers do not have to follow any particular rules for governing such access. However, if the client applications modify the message and save their changes, the store provider should follow certain rules:

  • Allow the first call to the IMAPIProp::SaveChanges method to proceed as if it were the only client that has the message open.
  • On the subsequent SaveChanges calls by other clients, the message store provider should ignore the changes and return MAPI_E_OBJECT_CHANGED.
  • Allow client applications to respond to a MAPI_E_OBJECT_CHANGED return code by calling SaveChanges again with the FORCE_SAVE flag. If a client application does this, the message store provider should replace the previous changes with the new ones.

Alternatively, the message store provider can detect the conflict and present an interface which allows the user to choose whether to keep the original message, overwrite the original message with the new changes, or save the new changes to another location.


Providing Read and Nonread Reports for Message Store Providers

If a message store provider can receive messages, it is required to support read reports and nonread reports of messages received by the message store provider. If a received message contains the PR_READ_RECEIPT_REQUESTED property and that property's value is TRUE, then the message store should send a notification message to the sender when the user opens the message indicating that the message has been read. Similarly, if the user deletes the message before opening it, the message store should issue a reply to the sender indicating that the message was not read.

Issuing these reports is a matter of creating an IMessage : IMAPIProp object, filling out the relevant properties on the message, and submitting it to the MAPI spooler as if the message had originated with the user. The IMAPISupport::ReadReceipt method can be used for this.

Note Special care must be taken when a message store makes copies of an unread message with pending read or nonread reports. Such reports should not be generated when users read any copies of a message for which reports have been requested. When making a copy of such a message, the message store provider should include the CLEAR_RN_PENDING and CLEAR_NRN_PENDING flags in its calls to IMAPIFolder::SetReadFlags and IMessage::SetReadFlag.


Implementing a Configuration Interface for Message Store Providers

Message store providers are required to implement an interface that allows the user to configure the message store provider to run on that user's computer. Typically, the message store provider is configured when the message store provider is added to a user's profile. The message store provider's configuration interface generally handles tasks such as setting user names and passwords for protected message stores, choosing paths to necessary files, and creating the underlying storage mechanism it will use, if necessary.

The configuration interface you implement is accessed through additional entry points in your message service provider's DLL. For more information, see Configuring a Message Service. The message store provider's configuration interface is the only user interface that a message store provider must implement.


Folder Associated Information Tables

MAPI defines the MAPI_ASSOCIATED flag for various MAPI components to use when dealing with associated information tables. Each folder in a message store should have an associated contents table table along with its standard contents table. Client applications store special messages in a folder's associated contents table to hold forms and views. In fact, to support forms and views, your message store provider must implement associated contents tables.

To implement associated contents tables, your store provider must
  • Support the MAPI_ASSOCIATED flag in the IMAPIContainer::GetContentsTable method so client applications can get the folder's associated contents table instead of the standard contents table.
  • Support the MAPI_ASSOCIATED flag in the IMAPIFolder::CreateMessage method so client applications can add messages to a folder's associated contents table.
  • Set the MAPI_ACCESS_CREATE_ASSOCIATED bit in the PR_ACCESS property on folder objects.
  • Support the DEL_ASSOCIATED flag in the IMAPIFolder::EmptyFolder method.
  • Set the MSGFLAG_ASSOCIATED bit in the PR_MESSAGE_FLAGS property for messages in the associated contents table.
  • Expose and respond to the PR_FOLDER_ASSOCIATED_CONTENTS property on folders.
  • Maintain the PR_ASSOC_CONTENT_COUNT property on folders.

There is no bit in the PR_STORE_SUPPORT_MASK property to indicate whether your message store provider supports associated contents tables. If your message store provider does not support them, it should return MAPI_E_NO_SUPPORT when client applications call any of the above methods with the MAPI_ASSOCIATED flag.


Sending Messages with Message Store Providers

Message store providers are not required to support outgoing message submissions — that is, the ability for client applications to use the message store provider to send messages. Client applications need to use a message store while sending messages because the message's data must be stored somewhere between the time that the user is finished composing it and the time that the MAPI spooler gives the message to a transport provider for submission to the underlying messaging system. If your message store provider does not support outgoing message submissions, it cannot be used as the default message store.

To support sending messages, your message store provider must
  • Implement an outgoing message queue.
  • Support the IMessage::SubmitMessage method on message objects created within the message store.
  • Support the IMsgStore methods that are specific to the MAPI spooler: IMsgStore::FinishedMsg, IMsgStore::GetOutgoingQueue, IMsgStore::NotifyNewMail, and IMsgStore::SetLockState.

The SetLockState method is important for proper interoperation between the MAPI spooler and clients. When the MAPI spooler calls SetLockState on an outgoing message, the message store provider must not let clients open the message. If a client does try to open a message that is locked by the MAPI spooler, the message store provider should return MAPI_E_NO_ACCESS. The locked state of a message does not have to be persistent in case the store is shut down while the message is locked by the MAPI spooler.

Regardless of whether the MAPI spooler has locked an outgoing message, the message store provider should not allow a message in the outgoing message queue to be opened for writing. If a client calls the IMSgStore::OpenEntry method on an outgoing message with the MAPI_MODIFY flag, the call should fail and return MAPI_E_SUBMITTED. If a client application calls OpenEntry on an outgoing message with the MAPI_BEST_ACCESS flag, the message store provider should allow read-only access to the message.

When a message is to be handled by the MAPI spooler, the message store provider sets the message's PR_SUBMIT_FLAGS property to SUBMITFLAG_LOCKED. The SUBMITFLAG_LOCKED value indicates that the MAPI spooler has locked the message for its exclusive use. The other value for PR_SUBMIT_FLAGS, SUBMITFLAG_PREPROCESS, is set when the message requires preprocessing by one or more preprocessor functions registered by a transport provider.

The following three procedures describe how the message store, transport, and MAPI spooler interact to send a message from a client to one or more recipients.

The client application calls the IMessage::SubmitMessage method.

In SubmitMessage, the message store provider
  1. Calls IMAPISupport::PrepareSubmit. If MAPI returns an error, the message store provider returns that error to the client.
  2. Sets the MSGFLAG_SUBMIT bit in the PR_MESSAGE_FLAGS property of the message.
  3. Makes sure that there is a column for PR_RESPONSIBILITY in the recipient table and sets it to FALSE to indicate that no transport has yet assumed responsibility for transmitting the message.
  4. Sets the date and time of origination in the PR_CLIENT_SUBMIT_TIME property.
  5. Calls IMAPISupport::ExpandRecips to:
    • Expand all personal distribution lists and custom recipients and replace all changed display names with their original names.
    • Remove duplicate names.
    • Check for any required preprocessing, and if preprocessing is required, set the NEEDS_PREPROCESSING flag and the PR_PREPROCESS property, a property reserved for MAPI.
    • Set the NEEDS_SPOOLER flag if the message store is tightly coupled with a transport and it cannot handle all of the recipients.
  6. Performs the following tasks if the NEEDS_PREPROCESSING message flag is set:
    • Puts the message in the outgoing queue with the SUBMITFLAG_PREPROCESS bit set in the PR_SUBMIT_FLAGS property.
    • Notifies the MAPI spooler that the queue has changed.
    • Returns control to the client, and message flow continues in the MAPI spooler. The MAPI spooler performs the following tasks:
1. Locks the message by calling IMsgStore::SetLockState.
2. Performs the needed preprocessing by calling all of the preprocessing functions in the order of registration. Transport providers call IMAPISupport::RegisterPreprocessor to register preprocessing functions.
3. Calls IMessage::SubmitMessage on the open message to indicate to the message store that preprocessing is complete.

Note The following two steps will occur in the client process if there was no preprocessing, and will occur when the MAPI spooler calls SubmitMessage if there was preprocessing.

  7. Performs the following tasks if the message store is tightly coupled to a transport and the NEEDS_SPOOLER flag was returned from IMAPISupport::ExpandRecips:
    • Handles any recipients that it can handle.
    • Sets the PR_RESPONSIBILITY property to TRUE for any recipients that it handles.
    • Performs the following tasks if all recipients are known to this tightly coupled store and transport:
1. Calls IMAPISupport::CompleteMsg if the message was preprocessed or the message store provider wants the MAPI spooler to complete message processing which is recommended so that messaging hooks can be invoked. Message flow continues with the MAPI spooler as described in the following procedure.
2. Performs the following tasks if the message was not preprocessed or the message store provider does not want the MAPI spooler to complete message processing:
· Copies the message to the folder identified by the entry identifier in the PR_SENTMAIL_ENTRYID property, if set.
· Deletes the message if the PR_DELETE_AFTER_SUBMIT property has been set to TRUE.
· Unlocks the message if it is locked.
· Returns to the client. Message flow is complete.

  • If the message was preprocessed or the provider wants the MAPI spooler to complete message processing (recommended so that messaging hooks can be invoked):
1. Calls IMAPISupport::CompleteMsg.
2. Message flow continues with the MAPI spooler. See Sending Messages: MAPI Spooler Tasks.

  • If the message was not preprocessed or the provider does not want the spooler to complete message processing:
1. Copies the message to the folder identified by the entry identifier in the PR_SENTMAIL_ENTRYID property, if set.
2. Deletes the message if the PR_DELETE_AFTER_SUBMIT property has been set to TRUE.
3. If the message is locked, unlocks it.
4. Returns to the caller. Message flow is complete.

  8. Performs the following tasks if the message store is not tightly coupled to a transport, not all of the recipients were known to the message store, or the NEEDS_SPOOLER flag is set:
    • Puts the message in the outgoing queue without setting the SUBMITFLAG_PREPROCESS bit in the PR_SUBMIT_FLAGS property.
    • Notifies the MAPI spooler that the outgoing queue has changed by generating a table notification.
    • Returns to the client, and message flow continues with a set of tasks performed by the MAPI spooler.


Receiving Messages with Message Store Providers

Message store providers do not have to support incoming message submissions; that is, the ability for transport providers and the MAPI spooler to use the message store provider as a delivery point for messages. However, if your message store provider does not support incoming message submissions, it cannot be used as the default message store.

To support incoming message submissions, your message store provider must
  • Support the IMsgStore::GetReceiveFolderTable and IMsgStore::GetReceiveFolder methods so client applications can find incoming messages.
  • Support the IMsgStore::NotifyNewMail method so that the MAPI spooler can inform the message store provider that a new message has arrived.
  • Implement notifications so that clients can register for new message notification. Strictly speaking, notifications are optional, but they are strongly recommended.

The sequence of method calls that occurs when an incoming message is delivered to a message store is:

  1. The MAPI spooler calls IMsgStore::OpenEntry with the Inbox's EntryID to get an IMAPIFolder interface.
  2. The MAPI spooler calls IMAPIFolder::CreateMessage to get a new message object.
  3. The MAPI spooler passes the message object to the transport provider.
  4. The transport provider fills in the message's properties with data from the underlying messaging system and calls the message object's IMAPIProp::SaveChanges method.
  5. The MAPI spooler calls any registered hook providers. The message may be modified, moved to a different folder, deleted, and so on.
  6. The message store provider uses its notification method to inform registered clients that a new message has arrived.
  7. The MAPI spooler calls the message store's IMsgStore::NotifyNewMail method.


Supporting Message Attachments for Message Store Providers

It is not required that your message store provider support message attachments. However, many client applications expect to be able to add attachments to messages. If your message store will be used to create or store IPM.Note messages, then you should support message attachments. Default message store providers are strongly encouraged to support message attachments. For more information, see Message Classes, and Default Message Stores.

There are five types of attachments that MAPI supports: file attachments, data attachments, message attachments, OLE object attachments, and links. The requirements for supporting each type are different. Clients differentiate between the two types of attachments by means of the PR_ATTACH_METHOD property on attachment objects.

Supporting attachments means implementing the IAttach : IMAPIProp interface. The IAttach interface has no methods of its own; it only has methods inherited from the IMAPIProp interface. Since your message store provider must already implement properties for message objects, this greatly simplifies the task of supporting attachments. Implementing IAttach basically means providing a way for clients to access a table of properties for particular attachments on messages.

Data attachments are simply attachments where the contents of the attachment are stored directly in an attachment's PR_ATTACH_DATA_BIN property. Data attachments exist primarily to allow clients to attach files to a message when the sender and the recipient of the message do not have access to a common file server. See PR_ATTACH_METHOD for details.

Message attachments are attachments where the attachment subobject is another IMessage : MAPIProp object. Since message store providers already support the IMessage interface, supporting message attachments is not difficult.

Supporting OLE object attachments means implementing the OLE IStorage, IStream, and IStreamDocfile interfaces. Your message store provider must be able to convert OLE object data stored in the message into an active OLE object when a client opens the object. For more information, see Attachment Properties.

Links come in two types: links to files and links to other messages. Links to files use the ATTACH_BY_REF_ONLY value for the PR_ATTACH_METHOD property along with PR_ATTACH_PATHNAME or PR_ATTACH_LONG_PATHNAME to specify the location of a file.

How one implements links to messages may be dependent on aspects of the local messaging system, and as such cannot be fully documented here. For example, sending a link to a message that is stored on a server-based message store is typically just a matter of sending the entry identifier of the linked message, providing that both the sender and recipient have access to that server. Other messaging system configurations present other requirements and challenges for implementing links to messages.


Supporting RTF Text for Message Store Providers

Some client applications allow users to use Rich Text Format (RTF) text in their messages. If your message store provider needs to support RTF text in messages, it needs to handle the PR_RTF_COMPRESSED property in addition to the PR_BODY property. Primarily, this means storing both properties, and making sure that PR_BODY contains a plain text version of the text in PR_RTF_COMPRESSED. The RTFSync function is useful for this.

There are two flags that can be set in the message store object's PR_STORE_SUPPORT_MASK property which tell clients what they can expect from the message store provider with respect to the PR_BODY and PR_RTF_COMPRESSED properties on messages within the message store. The STORE_RTF_OK flag indicates that the store can generate the value of the PR_BODY property from the PR_RTF_COMPRESSED property dynamically, which relieves clients from the burden of synchronizing them explicitly. The STORE_UNCOMPRESSED_RTF flag indicates that the message store provider can support uncompressed data in PR_RTF_COMPRESSED.

Message store providers that do not support RTF text need to delete the PR_RTF_IN_SYNC property when the PR_BODY property changes in order to interoperate properly with client applications that do support RTF text.


Providing Notifications for Message Store Providers

While notifications are optional, they are a very important part of a good message store provider. Client applications and the MAPI spooler rely on notifications from the message store provider to get good performance when submitting outgoing messages or receiving incoming messages. Clients and the MAPI spooler can function without receiving notifications from the message store provider but will not be able to inform users of changes in the message store without them. Typically, this means that users will be unable to see that a new message has arrived until their client next opens the message store's receive folder.

Clients register for notifications by calling the IMsgStore::Advise method. The client passes in an IMAPIAdviseSink object, a bitmask indicating what type of notifications the client is interested in receiving, and an EntryID indicating which object in the message store the Advise request applies to. When relevant events occur within the object — for example, when a new message arrives in the receive folder within the message store — the message store provider or the object itself should call the IMAPIAdviseSink::OnNotify method for all of the IMAPIAdviseSink objects that have registered for that event type.

Even if your message store provider never notifies other MAPI components of changes in the message store, it should still implement IMsgStore::Advise to return MAPI_E_NO_SUPPORT. This informs other components not to expect notifications from the message store provider.


Grouping and Restricting Tables in Message Store Providers

Client applications frequently allow users some control over how the contents of a folder are displayed. Typically, a user can choose to have messages grouped according to the value of one or more properties on the messages, or can choose to exclude messages matching some criteria from the list. This is done within the IMAPITable interface. Client applications can restrict the rows returned from the table to whatever criteria the user specifies. Therefore, a message store provider needs to implement the following IMAPITable methods.

IMAPITable method | Purpose
FindRow | Returns rows from a table that match the specified criteria.
QueryColumns | Returns the set of columns in a table or the set of currently used columns.
QueryRows | Returns one or more rows from a table starting from a given position.
Restrict | Applies a restriction to a table so that subsequent calls to FindRow only return rows that match the restriction.
SetColumns | Specifies which columns should be returned when rows are retrieved from the table.

Restrictions can be complex to implement; see About Restrictions for details. For more information on implementing tables, see Tables.


Supporting Searches in Message Store Providers

Client applications frequently have some user interface components devoted to searching for messages within a message store. Search criteria are specified within the IMAPIContainer interface by means of the IMAPIContainer::SetSearchCriteria and IMAPIContainer::GetSearchCriteria methods.

Clients use the message store object's PR_FINDER_ENTRYID property to identify the root folder in the message store that contains folders for search results. The search-results folder is often a folder at the top level of the message store that is not part of the IPM folder tree and is therefore hidden.

Whether your message store provider uses a permanent search-results folder or creates one when a client opens the entry identifier stored in the PR_FINDER_ENTRYID property is an implementation detail. It is somewhat easier for your message store provider to use a permanent folder that is created when the message store is created, because doing so avoids the complication of checking the entry identifier whenever any folder is opened to see whether to create a search-results folder. However, not all message store providers can do that; notably, read-only message stores or stores that provide a MAPI interface to a legacy database often are not allowed or are unable to create a permanent search-results folder in the underlying storage mechanism.


Generating and Using Entry Identifiers in Message Store Providers

When a new folder or message is created in a message store, the message store provider has to assign that object an entry identifier so that client applications can refer to it. This brings up the option of reusing the defunct long-term entry identifiers of deleted objects or not. There is no requirement one way or the other for message store providers, although if it is feasable, it is better if a message store provider always generates new long-term entry identifiers for new objects rather than reusing old ones. It is fine to reuse short-term entry identifiers when the objects they refer to are deleted.

The reason for this is that clients can cache entry identifiers, sometimes for long periods of time. If that happens and the message store provider does reuse entry identifiers, then it is possible for the entry identifier to refer to a different object when the client opens the entry identifier than when it first obtained the entry identifier. If the message store provider does not reuse entry identifiers — or at least uses an entry identifier generation scheme that does not repeat for a very long time — this problem cannot occur.

Similarly, it is good for message store providers to attempt to preserve entry identifiers for folders and messages when they are moved within the message store. If the message store provider can do that, references to objects in the store will not become invalid when the object is moved to a different location within the store.


Default Message Stores

A default message store is one that client applications can use for general purpose messaging tasks. There are a number of optional features for message store providers that become required if the message store provider is to be used as the default message store. They are:

  • Implementing the special folders: Inbox, Outbox, and search-results folder.
  • Providing read and nonread reports.
  • Allowing incoming and outgoing message submissions.
  • Allowing creation of messages with arbitrary message classes.
  • Supporting named and multivalued properties.
  • Supporting the IMSProvider::SpoolerLogon method, even if the message store provider is tightly coupled with a transport provider.
  • Supporting associated contents tables.
  • Supporting notification of the MAPI spooler when there are messages in the outgoing message queue.


Read-Only Message Stores

A read-only message store is one in which neither the MAPI client nor the MAPI spooler can create, modify or delete the objects in the message store. There are many reasons why you might want to implement a read-only message store. For example, a credit reporting firm could use a read-only store to allow its customers or employees to see but not change individual credit reports. Choosing to make a read-only message store has implications for the structure of the store provider and for the store itself. For example, a read-only message store can't have an Outbox folder because then MAPI clients would request that new outgoing messages be created in that folder. Similarly, it is the store provider's responsibility to ensure the integrity of the underlying storage mechanism.

There are three flags that can be set in the message store's PR_STORE_SUPPORT_MASK property which support different levels of read-only access. the STORE_READONLY flag indicates that all IMAPIProp interfaces on objects within the message store are read-only. The STORE_MODIFY_OK flag indicates that existing messages in the message store may be modified, but new folders and messages may not be created. The STORE_CREATE_OK flag indicates that new messages and folders may be created, but indicates nothing about whether existing objects may be modified.

The fact that MAPI clients and the MAPI spooler may not be able to create, modify or delete objects in the message store does not mean that the contents of the underlying storage mechanism never change. Nor does it mean that your store provider never needs write access to the underlying storage mechanism. In some circumstances those two conditions may apply, but not in the general case of a read-only message store. What level of access your store provider requires and whether or not your store provider ever changes data in the underlying storage mechanism depends mainly on the specific nature of your store provider.

For example, if you are writing a store provider to give MAPI clients access to a database stored on a CD-ROM device, then the underlying storage mechanism cannot change and your store provider can only have read access to it. If, however, you are writing a store provider to give MAPI clients read-only access to a public folder database but the store provider needs to keep track of the read/unread status of messages for each user, then the store provider will need to write new data to the underlying storage mechanism. However, in neither example does the store provider ever have to create, modify, or delete folders or messages at the request of MAPI clients or the MAPI spooler.

The list of reasons that a store provider would need to write data to an underlying storage mechanism that is otherwise read-only is fairly short:

  • To store the read/unread status of messages.
  • To implement read/non-read notifications.
  • To store views.
  • To cache persistent indexes for user defined folder sort orders.
  • To store what order a folder's contents are sorted in (supporting IMAPIFolder::SaveContentsSort).
  • To store search criteria, search state, and results, if the message store provider supports searches (supporting IMAPIContainer::SetSearchCriteria).

If your message store provider can never write data to the underlying storage mechanism, it will need to implement these features using a separate storage mechanism outside of the underlying storage mechanism. For example, a read-only message store provider could store the read/unread status of messages in the store in a file on the user's computer. This strategy presents additional difficulties but may be the only feasable way for read-only message store providers to implement some features. For example, keeping the contents of the separate storage mechanism synchronized with the objects in the message store is more difficult than storing the read/unread status directly in the message store itself.

Searching presents an additional complication for read-only message store providers. Clients use the folder specified in the message store object's PR_FINDER_ENTRYID property to locate the folder used for search results. Read-only message store providers often cannot install a permanent search-results folder into the message store. In that situation, the message store provider should store an entry identifier in the PR_FINDER_ENTRYID property that it can recognize when clients open folders so that it can dynamically create a search-results folder instead of reading one from the underlying storage mechanism. However, since many read-only message store providers create all their folders dynamically, this is usually not too much of a burden.

The fact that your message store provider is read-only is advertised in the store provider object's PR_STORE_SUPPORT_MASK property. However, do not count on clients to respect that property; your store provider's code should enforce the read-only status of the underlying storage mechanism.


Supporting Forms and Views in Read-Only Message Stores

If your message store provider allows read-only access to the underlying storage mechanism, then client applications and the MAPI form manager will be unable to do certain things. Specifically, clients will be unable to add or modify custom views, and the MAPI form manager will be unable to install forms in the associated contents tables of the store's folders.

For many read-only message stores, that may not be a problem. If that is the case, then the message store provider does not need to support associated contents tables at all. However, if your message store provider must be read-only and it must also support a predefined set of views or forms, then it will need to support associated contents tables.

The most common strategy for doing this, since clients and the MAPI form manager cannot install the views or forms into the message store themselves, is for the message store provider to hard-code them into the message store. This means that the associated contents table or tables containing the views or forms will exist in the message store when it is created, before any clients or the MAPI form manager ever access it. Then, when a client requests an associated contents table to get custom views from a form or the MAPI form manager requests an associated contents table in order to launch a form, the message store provider can provide one.

This requirement that the associated contents tables be created and populated when the message store itself is created implies that your message store provider will need to obtain information about the format of the special messages that clients and the MAPI form manager use in order to store views and forms. What those formats are will depend on the client and MAPI form manager being used, and so a description of them cannot be provided here. If you do not have access to that information, it is very likely that you will have to reverse engineer those formats from existing message stores that have views and forms installed into them. The MAPI SDK includes a utility called MDBVIEW.EXE which you can use to view the properties and their values of objects in message stores to help with this reverse engineering.

The danger in implementing forms and views by reverse engineering the form and view descriptor format of a MAPI client is that if the client changes that format when it is upgraded, the forms and views in your message store will no longer function. This problem will persist until a universal format for form and view descriptors, defined by MAPI, is available. For this reason, reverse engineering form and view descriptors should only be done as a last resort.


Tightly Coupled Message Store Providers

Message store providers can be "tightly coupled" with a transport provider. Tightly coupling MAPI service providers means implementing the two providers such that the store provider and transport provider can communicate to make the process of sending and receiving messages more efficient. The benefit of doing this is that performance improvements can result when two service providers can interact with each other directly rather than by means of the MAPI spooler. To tightly couple a message store provider to a transport provider, the transport provider must place the message store provider's entry identifier in the PR_OWN_STORE_ENTRYID property in the transport provider's row in the MAPI status table. This enables the MAPI spooler to connect the store provider to the transport provider.

There is no requirement that a message store provider ever be tightly coupled with any other service provider. The most common service provider to tightly couple with a message store provider is a transport provider. This is usually done so that sending and receiving messages can be accomplished without involving the MAPI spooler. For example, when the user submits an outgoing message, the combined message store provider and transport provider can send it directly. The combined service providers don't have to first notify the MAPI spooler that there is a new message to process and then wait for the MAPI spooler to initiate the process of transferring the message from the message store provider to the transport provider. This has particular benefits when a server-based message store is being used by minimizing network traffic between the user's computer and the server.

In general, there are no well-specified procedures for tightly coupling service providers. However, there are some guidelines:

  • Keep in mind that if the reason for tightly coupling service providers is performance, then they are taking other parts of the MAPI subsystem out of the processes that those parts would normally be involved in. This implies that the individual parts within the combined service provider should interact with each other in a way that simulates the interaction they would normally have with the parts of the MAPI subsystem that are not being used.
  • When tightly coupled service providers do interact with other MAPI components, they must still interact with them in exactly the way they would if they were not tightly coupled. For example, if a user is using a combined message store provider/transport provider as their default message store but is using a separate transport provider to send messages — as can happen when a user takes his or her computer on the road and switches to a remote transport provider — the message store portion of the tightly coupled service provider must still interact with the MAPI spooler just as if it were a standalone message store provider.


Loading Message Store Providers

When a client application opens a message store, MAPI loads the message store provider's DLL into memory. After loading the DLL, a very specific sequence of method calls occurs between the message store provider and MAPI. This method call sequence enables MAPI to get top-level IMSProvider:IUnknown IMSLogon:IUnknown, and IMsgStore:IMAPIProp objects, and allows the message store provider to get a MAPI support object. After the call sequence, the message store provider should be ready to accept logons from clients.

The call sequence when a message provider DLL is loaded is:

  1. Client calls IMAPISession::OpenMsgStore.
  2. If the message store is not already open, MAPI loads the store provider's DLL and calls the DLL's MSProviderInit entry point. If the message store is already open, MAPI skips steps 2 and 3, then uses the existing IMSProvider object to complete step 4.
  3. MSProviderInit creates and returns an IMSProvider object.
  4. MAPI calls IMSProvider::Logon, passing the client application's message store entry identifier.
  5. IMSProvider::Logon creates and returns an IMSLogon object and an IMsgStore object, then calls the IUnknown::AddRef method on its IMAPISupport:IUnknown object. If the client's message store entry identifier refers to a message store that is already open, the message store provider can return existing IMSLogon and IMsgStore objects, and does not need to call AddRef on its support object.
  6. If the client did not set the MAPI_NO_MAIL flag when it logged on and it did not set the MDB_NO_MAIL in step 1, then MAPI gives the message store's entry identifier to the MAPI spooler so the MAPI spooler can log on to the message store.
  7. MAPI returns the IMsgStore object to the client.
  8. The MAPI spooler calls IMSProvider::SpoolerLogon.
  9. IMSProvider::SpoolerLogon returns the same IMSLogon object and IMsgStore object from step 5.

Note If the logon call to the message store provider fails because an incorrect password was supplied and the message store provider cannot display an interface to ask for the correct password, it should return MAPI_E_FAILONEPROVIDER from the IMSProvider::Logon method. This will allow clients to prompt the user for a password to try logging on to the message store provider again instead of causing MAPI to fail the provider for the entire session.


Developing MAPI Form Servers

This section details the process of creating form server executable and form configuration files for creating custom MAPI forms. Before reading this section, you should familiarize yourself with the information in Forms.

Developing a form server includes:

  1. Deciding what information the form will carry and choosing a set of properties to hold that information. See Choosing a Form's Property Set.
  2. Designing a user interface to allow users to interact with the form's properties.
  3. Choosing a message class and generating a unique class identifier (CLSID). For an overview of message classes, see Message Classes. For more information about message classes and forms, see Choosing a Message Class and Creating a New Interpersonal (IPM) Message Class.
  4. Implementing the required MAPI form interfaces, as well as any optional interfaces that your particular form server needs. See Writing Form Server Code.
  5. Writing user interface code to handle the user's interaction with the form object and the properties the form uses.
  6. Creating a form configuration file for the form. See File Format of Form Configuration Files.
  7. Installing the form on users' computers. See Installing a Form Into a Library.

You will most likely perform steps 1–5 simultaneously rather than completing them in sequence. The process of developing a form server, like many programming projects, is not one in which there is a particularly well-defined starting point and ending point. For example, creating a form configuration file is listed as the last step in this process, but your form configuration file will probably be created incrementally and will become more complete as you add features to your form server.


Choosing a Form's Property Set

When you implement your form server, you need to have a property for each piece of information that your message class needs. These properties can be predefined MAPI properties, or they can be custom properties that you define. For details about working with properties, see Properties.

Your form configuration file will contain a list of properties that your form server exposes for client applications to use, but this does not have to be the entire list of properties used by your form server. Client applications typically use the exposed properties to allow users to sort messages in a folder or customize their interfaces in some way.

MAPI has a large set of predefined properties that suffice for most applications. However, there will be times when a custom message class needs a property that MAPI does not define. You can use custom properties to extend the MAPI predefined set of properties for whatever special information your form server needs to support.

Custom properties can be defined by:

  • Choosing a name for the property and using the IMAPIProp::GetIdsFromNames method to obtain a property tag for it. The IMAPIProp interface through which you call this method comes from the IMessage pointer that is passed to the form server when the message is created. Note that the property name must be a wide-character string.
  • Defining a custom property tag yourself. Custom property tags must be in the range 0x6800-0x7BFF. Properties in this range are message class specific.

For details about defining custom properties, see Defining New Properties.

Note Form servers that have a message text often use the PR_RTF_COMPRESSED property to store it. If your form server uses PR_RTF_COMPRESSED, it should also ensure that the PR_BODY property contains a text-only version of the message text, in case the resulting message is read by a client that does not support Rich Text Format (RTF) message text.


Choosing a Message Class

As described in Message Classes, message classes are an important concept for establishing the relationship between types of custom messages, and by extension, between form servers themselves. Fortunately, choosing a message class string is fairly simple. The message class string of a message class is an arbitrary string, but should follow these conventions:

  • The string should satisfy all the conventions described in the documentation for PR_MESSAGE_CLASS. Importantly, the string should be composed entirely of ANSI characters and be less than 256 characters long.
  • If your form server is derived from an existing form server or is an extension of an existing form server, your message class string should be formed by adding a period and another word to the message class string of the form server your form is based on. For example, imagine that your are implementing a form for rescheduling a meeting, and your form is based on an existing form for scheduling meetings. If the meeting scheduling form's message class string is "IPM.Meeting", your message class string could be "IPM.Meeting.Reschedule".
  • If your form is not based on any existing form, your message class string should still begin with either the IPM. or IPC. prefix, depending on whether the form is intended to be received by a person or by another piece of software. IPM. designates an interpersonal message that usually ends up in a user's Inbox, and IPC. designates an interprocess communication message that is not typically delivered to a user's Inbox.
  • If your message class is intended to be human-readable, the message class string should start with IPM. A message class is generally considered human-readable if it uses any properties that contain plain text or Rich Text Format (RTF) data. If your form uses the PR_BODY property, it should almost certainly use an IPM.-derived message class string. For example, if you are implementing a form for purchase orders, and your organization requires that purchase orders be approved by a manager, your message class string could be IPM.Purchase_Order. Forms that are designed for use with public folders or public folder applications are typically considered to be interpersonal because they are read by people even though they are not actually addressed to any person's e-mail address. The typical prefix for public folder message classes is IPM.post.
  • If your message class is intended to be received by some other piece of software instead of by a person, the message class string should start with IPC. For example, if you are implementing a form for allowing people to automatically subscribe to mailing lists, your message class string could be IPC.Subscribe.
  • Your message class string should never end with a period.

The message class string should be put in the [Description] section of the form configuration file, in the MessageClass entry, like this:

MessageClass=IPM.Meeting.Reschedule

Once you have chosen an appropriate message class string, you should generate a class identifier for it. Class identifiers are generated with the UUIDGEN.EXE utility that is included with the Platform SDK. The class identifier must be put in the form configuration file's CLSID entry, along with the MessageClass entry, like this:

CLSID={88FFF551-B8C5-11ce-8DE0-00AA0060D242}

Your class identifier will almost certainly be different, of course. For details, see Creating a Form Configuration File.

When the form is installed on a user's computer, your installation process — whether it is a setup program or something else — must make a registry entry in the HKEY_CLASSES_ROOT\CLSID\ section of the registry for the class identifier. This entry must be set to the message class string. For example, you would create a registry entry like this for the example class identifier above:

HKEY_CLASSES_ROOT\CLSID\{88FFF551-B8C5-11ce-8DE0-
    00AA0060D242}="IPM.Meeting.Reschedule"

For details, see Installing a Form into a Library.


Form States

Form objects can be in one of five distinct states, depending on what methods have been called in them and whether any errors have occurred in performing those methods. The states are described in the following topics:

Uninitialized State

Normal State

No Scribble State

Hands Off After Save State

Hands Off From Normal State

The states primarily relate to the status of the data in the form object. The different states reflect whether the data needs to be saved, whether the form object should allow modifications to the data, and what point in the process of saving the data the form is in. As such, the form states and transitions between them have more to do with your form server's implementation of IPersistMessage interface methods than any other. Knowledge of these states is very useful for proper implementation of the MAPI form interfaces that your form server must implement.

Each state is described in the following sections, along with the legal actions that cause transitions to other states. Any transitions not listed in the following sections are illegal. If your form objects make illegal transitions between states, they will not behave in the ways that messaging clients expect and could cause unpredictable client or form object behavior.

Note Some state transitions depend on information from previous states. Your form server will most likely have to implement a "dirty" flag in its form objects to indicate whether the values of the message's properties have been changed in order to facilitate later state changes.


Uninitialized State

The Uninitialized state is the initial state form objects should be in when they are first created. Form objects become initialized with message data when a client application calls the IPersistMessage::InitNew or IPersistMessage::Load method on the form object. Legal state transitions from the Unitialized state are described in the following table.

IPersistMessage method | Action | New state
InitNew | Load the form object with default data. | Normal
Load | Load the form object with data from the target message. | Normal
GetClassId | Return success, or set the last error to and return E_UNEXPECTED. | Uninitialized
GetLastError | Return the last error. | Uninitialized
Other IPersistMessage methods or methods from other interfaces | Set the last error to and return E_UNEXPECTED. | Uninitialized


Normal State

The Normal state is where the form object spends most of its time, waiting for client applications to initiate an action such as saving changes or closing the form. Legal transitions from the Normal state are described in the following table.

IPersistMessage method | Action | New state
Save( pMessage == NULL, fSameAsLoad == TRUE) or Save( pMessage != NULL, fSameAsLoad == FALSE) | Recursively save any embedded OLE objects that are dirty. Save message data back to the message object. Store the fSameAsLoad flag for later use in the No Scribble state. | No Scribble
Save( pMessage != NULL, fSameAsLoad == TRUE) | This is the same as the previous case, except that this Save call is used in low memory situations and must not fail for lack of memory. | No Scribble
HandsOffMessage | Recursively invoke the HandsOffMessage method on embedded messages or the OLE IPersistStorage::HandsOffStorage method on embedded OLE objects. Release the message object and any embedded messages or objects. | Hands Off From Normal
SaveCompleted, InitNew or Load | Set last error to and return E_UNEXPECTED | Normal
GetLastError | Return the last error. | Normal
Other IPersistMessage methods or methods from other interfaces | Implement as described in the documentation for the IPersistMessage interface. | Normal


No Scribble State

The No Scribble state indicates that changes to a message are being saved. The actual saving of values stored in the form object's user interface occurs when the form object's IPersistMessage::Save method is called by the client application. Legal transitions from the No Scribble state are described in the following table.

IPersistMessage method | Action | New state
SaveCompleted( pMessage == NULL) | If fSameAsLoad flag was TRUE on the Save call that caused the form to enter the No Scribble State and the message has been modified, then internally mark the changes as saved and call IMAPIViewAdviseSink::OnSaved. | Normal
SaveCompleted( pMessage != NULL) | Call the IPersistMessage::HandsOffMessage method (similar to the OLE IPersistStorage::HandsOffStorage method) followed by the normal SaveCompleted actions. If SaveCompleted was successful, enter the Normal state. Otherwise, enter the Hands Off After Save state. | Normal or Hands Off After Save
HandsOffMessage | Recursively invoke the HandsOffMessage method on embedded messages or the OLE IPersistStorage::HandsOffStorage method on embedded OLE objects. Release the message object and any embedded messages or objects. | Hands Off After Save
Save, InitNew or Load | Set the last error to and return E_UNEXPECTED. | No Scribble
GetLastError | Return the last error. | No Scribble
Other IPersistMessage methods or methods from other interfaces | Set the last error to and return E_UNEXPECTED. | No Scribble


Hands Off After Save State

The Hands Off After Save state is part of the process of saving the contents of a form to permanent storage. When in this state, the form object should refrain from making changes to the in-memory copies of values of the message's properties, since there may not be another opportunity to save those changes. Legal transitions from the Hands Off After Save state are described in the following table.

IPersistMessage method | Action | New State
SaveCompleted( pMessage != NULL) | Open any embedded objects. The data in the message stored in pMessage is guaranteed to be the same as the message in the previous Save call. If the SaveCompleted call succeeds, enter the Normal state. Otherwise, set the last error to E_OUTOFMEMORY and stay in the Hands Off After Save state. | Normal or Hands Off After Save
SaveCompleted( pMessage == NULL) | Set the last error to E_INVALIDARG or E_UNEXPECTED | Hands Off After Save
HandsOffMessage, Save, or InitNew | Set the last error to and return E_UNEXPECTED | Hands Off After Save
Load | Load the form object with data from the target message. This call can occur when the form object is going to the next or previous message in a folder. | Normal
GetLastError | Return the last error. | Hands Off After Save
Other IPersistMessage methods or methods from other interfaces | Set the last error to and return E_UNEXPECTED | Hands Off After Save


Hands Off From Normal State

The Hands Off From Normal state is very similar to the Hands Off After Save state. It is part of the process of saving the contents of a form to permanent storage. When in this state, the form object should refrain from making changes to the in-memory copies of values of the message's properties, since there may not be another opportunity to save those changes. Legal transitions from the Hands Off From Normal state are described in the following table.

IPersistMessage method | Action | New state
SaveCompleted( pMessage != NULL) | Replace the message object's message with pMessage, which is the replacement for the message revoked by the previous call to HandsOffMessage. The data in the new message is guaranteed to be the same as in the revoked message. The message should not be marked as clean, nor should IMAPIViewAdviseSink::OnSaved be called after this call. If the SaveCompleted call succeeds, enter the Normal state. Otherwise, stay in the Hands Off From Normal state. | Normal or Hands Off From Normal
SaveCompleted( pMessage == NULL) | Set the last error to E_UNEXPECTED. | Hands Off From Normal
HandsOffMessage, Save, InitNew, or Load | Set the last error to E_UNEXPECTED | Hands Off From Normal
GetLastError | Return the last error. | Hands Off From Normal
Other IPersistMessage methods or methods from other interfaces | Set the last error to E_UNEXPECTED | Hands Off From Normal


Writing Form Server Code

A form server can be thought of as three things: a Win16 or Win32 program that displays an interface and handles windows messages by way of the standard Windows message pump mechanisms, an object that registers its class factory with OLE and is activated by OLE automation methods, and a MAPI object that follows the MAPI rules for interactions with other MAPI components. Your code has to handle all three of those broad requirements simultaneously.

See the COM and ActiveX Object Services section in the Platform SDK for details about registering your form server's class factory. Handling windows messages and displaying an interface are standard Windows programming techniques that don't have any special requirements with respect to MAPI forms. Again, the Platform SDK has details about Windows programming. This document contains what you need to know to implement the required and optional MAPI form interfaces so that they follow the MAPI rules for interactions with other MAPI components — primarily the MAPI Form Manager and messaging client applications.

All of the interfaces that you can use when implementing form servers are derived — either directly or indirectly — from the OLE base class IUnknown. This means that all your implementations of these interfaces will need to have QueryInterface, AddRef, and Release methods. You can save yourself a lot of work if you use multiple inheritance to implement all of the required interfaces in one new class of your own, so that all the interfaces you are using can share a single implementation of the required IUnknown methods. See the OLE documentation on the IUnknown class methods for details on the QueryInterface, AddRef, and Release methods. There are no special considerations with respect to MAPI form servers for these methods.

While not all of the MAPI form interfaces are mandatory for all form servers, the methods in any given interface are. That is, if you choose to implement a particular interface, you must implement all of the methods in the interface. This is different from the situation with some other MAPI components, such as message transports. Fortunately, the methods in the MAPI form interfaces are relatively straightforward so implementing all of them does not put a great burden on developers.

The MAPI form interfaces are independent of the type of development tool used to create a form server. This allows forms to be created using different development tools such as Microsoft® Visual C++® and tools from other vendors. The only requirement is that all form servers must support the required MAPI form interfaces.

Note It is possible to implement form servers using a mix of languages. For example, you could use Microsoft® Visual Basic® for the form's user interface and Microsoft® C/C++ for the underlying MAPI code. However, this document relates only to C++ development of form servers.

Not all of the MAPI interfaces relating to forms are required by all form servers. The optional interfaces allow you to implement some advanced form functions that are not needed by most form servers. The following table lists the interfaces, what they are for, and whether you must implement them.

Interface | Usage | Status
IMAPIForm | The primary interface that clients use when loading form servers, executing form verbs, and shutting down form servers. Also the OLE IUnknown – derived interface used to inform other OLE components what interfaces a form object implements. | Required
IPersistMessage | Used when loading messages into and saving messages from form objects. | Required
IMAPIFormAdviseSink | Used by form objects to keep track of messaging client status and to find out whether the form object is capable of displaying the next or previous message in a folder. | Optional
IClassFactory | OLE class factory interface used by form objects for compliance with the OLE class factory mechanism. | Required
IMAPIFormFactory | Used if your form server supports more than one type of form. In this case, the IMAPIFormFactory interface allows client applications to access the multiple IClassFactory interfaces (one per type of form that your form server supports) that your form server must also implement. | Optional


Declaring Form Interfaces

You can simplify the declarations of your implementations of MAPI form interfaces by using the MAPI_interface_METHOD macros, where interface is a form interface defined in the MAPIFORM.H header file. You are not required to use these macros, but if you do not you should take particular care that your declarations conform to the declarations in the MAPIFORM.H header file. For example, you could declare your form server's form object class like this:

class CMyForm : public IPersistMessage, public IMAPIForm,
                public IMAPIFormAdviseSink
{
public:
    CMyForm(CClassFactory *);    // ctor takes a class factory object
    ~CMyForm(void);

// MAPI methods that need to be implemented.
    MAPI_IUNKNOWN_METHODS(IMPL);
    MAPI_GETLASTERROR_METHOD(IMPL);
    MAPI_IPERSISTMESSAGE_METHODS(IMPL);
    MAPI_IMAPIFORM_METHODS(IMPL);
    MAPI_IMAPIFORMADVISESINK_METHODS(IMPL);

// other implementation specific stuff:

};


Integrating MAPI Form Server Code with Windows Code

Recall that your form server is a Win32 or Win16 program. As such, there are some tasks related to loading your form server into memory and exiting cleanly. Like all Windows programs, the entry point for your form server is the WinMain function. This function is the appropriate place to perform the following tasks:

  • Creating and registering a window class so that your form server can interact with other OLE components.
  • Creating and registering a window class or classes for your form objects' user interfaces.
  • Calling the MAPIInitialize function. MAPIInitialize handles the required OLE initialization for you as well. This must be done once per instance of your form server.
  • Registering a global atom with a string representation of the form server's class identifier (CLSID). This atom should exist for the lifetime of the form server.
  • Calling the OLE function CoRegisterClassObject to register your form server's class factory with OLE.
  • Creating a main window to receive messages. This window probably does not need to be visible since the user will be interacting with the specific windows associated with individual form objects. However, during development, the main window can be a convenient place for debugging output or control of your form server.
  • Creating a message loop which runs for the lifetime of the form server, translating and dispatching windows messages to active form objects.

When your form server exits, it should perform the following tasks:

  • Call the OLE function CoRevokeClassObject to revoke your message class's OLE registration.
  • Call MAPIUninitialize to properly close the form server's connection to MAPI.
  • Delete the global atom containing the string representation of the class identifier.


Implementing the IClassFactory Interface for Form Servers

IClassFactory is the OLE interface that client applications use to create new form objects of your form server's message class. The following table lists the IClassFactory methods that are required.

Method | Use
CreateInstance | Creates a new form object.
LockServer | Locks the form server in memory so that startup overhead can be avoided when multiple form objects are created.

For all the information necessary to implement these methods, see the COM and ActiveX Object Services section in the Platform SDK.


Creating A Form Configuration File

A form configuration file provides information about a form both to the form manager being used and to client applications. A form configuration file contains an extensive specification for a form, including the properties published by the form for use by messaging clients, the verbs implemented by the form, and the platforms supported by the form.

A form configuration file is a file with a .CFG extension, and has a format similar to a Windows initialization file. It is a plain text file with a number of sections. Each section begins with a section name, enclosed in square brackets. Each section contains one or more lines which define values and settings relevant to that section. Values have one of the following types:

  • String
  • Displayed string
  • Platform string
  • Path name
  • Integer
  • GUID

For detailed information about the sections of a .CFG file, see File Format of Form Configuration Files.


Form Server Interactions

The subtopics in this section describe interactions between client applications, the MAPI form manager, form servers, and form objects for a variety of common actions such as opening a message and composing a new message.


Retrieving Form Properties

To issue a query meaningful to a custom message type, an application needs to know the properties expected on that message. To get a list of properties used by a custom message class, a client application queries the MAPI form manager. The form manager gets this information from the appropriate form configuration file so that this information can be used by client applications without the overhead of activating the form server itself. To do this, the client application calls IMAPIFormMgr::ResolveMessageClass, like this:

IMAPIFormInfo *pfrminf = NULL;
hr = pfrmmgr->ResolveMessageClass("IPM.Demo", 0L, NULL, &pfrminf);

Note that the third argument to ResolveMessageClass is the folder containing the associated contents table that the query will search for form servers. NULL indicates that the form manager should search all available form containers. If the query is to run against a particular folder it is better to include the appropriate IMAPIFolder pointer instead.


Launching a Form to Read a Message

Form server implementers should expect the following sequence of method calls to their form server and form objects when a client application loads a message:

  1. The client application opens the form manager with a call to MAPIOpenFormMgr.
  2. The client application calls IMAPIFormMgr::LoadForm, which returns an object with IMAPIForm. The form manager may be released now if it won't be used for further form activations. Note that a call to LoadForm may take some time because the form manager may have to install the form server's executable files before proceeding.
  3. Optionally, the client application can prepare IMAPIViewContext to control operations which may cause the form object to load the previous or next message in the folder. The client application can use IMAPIForm::SetViewContext to change the default view context that was set in the LoadForm call.
  4. The client application calls IPersistMessage::Load to load message data into the form object.
  5. The client application calls IMAPIForm::DoVerb to invoke the "open" verb, passing the optional IMAPIViewContext interface pointer.


Launching a New Compose Form

Form server implementers should expect the following sequence of method calls to their form server and form objects when a client application opens a new message for composing:

  1. The client application calls IMAPIFormMgr::ResolveMessageClass to get class information about the form server's message class.
  2. The client application calls IMAPIFormMgr::CreateForm to get a new form object.
  3. The MAPI form manager loads the form server, if it is not already in memory and gets an IMAPIForm object from the form server.
  4. The client application takes the resulting IMAPIForm object and calls the QueryInterface method to get the object's IPersistMessage interface.
  5. The client application calls IPersistMessage::InitNew to associate the form object with IMessage, view context, and advise sink objects.
  6. The client application calls IMAPIForm::DoVerb to invoke the "open" verb.


Launching a Form Server

The series of interactions that occurs when a form is loaded from persistant storage — that is, from a form library — to display a message is as follows:

  1. The messaging client gets the message's message class, message flags and message status. This step is optional; if these pieces of data are not provided in step 2, the form manager will retrieve them.
  2. The messaging client calls IMAPIFormMgr::LoadForm with the target message.
  3. The form manager loads the form server from the appropriate form library. If the form server for the target message is not installed, the form manager installs the form's executable files as well.
  4. The form manager calls IUnknown::QueryInterface on the form object to obtain the form object's IMAPIForm and IPersistMessage interfaces.
  5. The form manager calls IPersistMessage::Load with the message site and message interfaces from the viewer object.
  6. The form object calls back to the messaging client's IMAPIMessageSite::GetSiteStatus method.
  7. The form manager calls the form object's IMAPIForm::SetViewContext with the view context interface from the messaging client.
  8. The form object calls back to the messaging client's IMAPIViewContext::SetAdviseSink method.
  9. The form object calls back to the messaging client's IMAPIViewContext::GetViewStatus method.
  10. The messaging client calls the form object's IMAPIForm::Advise method with the view context interfaces from the viewer object and the message site object.
  11. The messaging client calls the form object's IMAPIForm::DoVerb method.
  12. The form object creates its user interface, if necessary, and interacts with the user.


Installing a Form into a Library

The default MAPI form manager supplied with the Platform SDK does not provide a user interface for installing forms in the various form libraries. Because of this, you will have to create a small application — or detailed set of instructions — that users can use to install the form.

If you implement an install application, the series of actions it must do to install a form into a folder's associated contents table are as follows:

  1. Call the MAPIOpenFormMgr function to open the form manager.
  2. Use IMAPIFormMgr::OpenFormContainer or IMAPIFormMgr::SelectFormContainer to select and open the target container for the form.
  3. Use the IMAPIFormContainer::InstallForm function to install the form.

Steps 4-6 are for installation into a local form library:

  4. Copy all files to the appropriate place on the local disk, if installation is to the local form library on the user's workstation. If necessary, modify the form configuration file to reflect current pathnames of components. The form configuration file can contain relative pathnames in which case this step may not be necessary.
  5. Do the appropriate OLE registration to associate the message type with the form server being installed.
  6. If the form was installed into the local form library, copy the form's icon (.ICO) and configuration (.CFG) files into the %WINDOWS%\FORMS\CONFIGS directory for auto-restore in the event that the form library is corrupted or deleted. This step is recommended but not mandatory.

Note Installation to a local form library can be simplified by replacing steps 1 and 2 with a call to MAPIOpenLocalFormContainer.


Developing a Hook Provider or Preprocessor

MAPI defines two types of extensions that it uses to allow custom code to be inserted into the message transmission and reception processes—hook providers and preprocessors. A hook provider, also called a spooler hook, can be called after an outbound message reaches the transport providers and before an inbound message is delivered to the default folder for its message class. Preprocessors operate on outbound messages only and are called before and after transport providers handle the message.

Since hook providers and preprocessors act during the message sending and receiving processes, you should familiarize yourself with the roles that other MAPI components play in these processes. Specifically, you should read Sending Messages with MAPI, Service Provider Basics, Developing a Transport Provider, and Developing a Message Store Provider. You do not need to learn the material in these sections in any great detail in order to implement a hook provider or preprocessor, but you should have a basic understanding of the way these components interact to send and receive messages.

There are several things to consider when choosing whether to use a hook provider or a preprocessor to implement your custom code:

  • Whether your component needs to be able to operate on inbound messages. If it needs to act on inbound messages, you must use a hook provider, since preprocessors are not called for inbound messages.
  • Whether your component needs to operate before or after transport providers for outbound messages. Preprocessors are called before transport providers, hook providers are called after.
  • What your component needs to do. Preprocessors are typically used to modify a message's contents or recipient list before sending. For example, a preprocessor can be used to automatically add a signature to outgoing messages. Hook providers are typically used to archive messages or automatically file them in different folders; that is, to manipulate the relationship between the message and its message store although they can also modify a message's content. Hook providers cannot, however, modify a message's recipients. Only preprocessors can cause a message to be sent to different recipients than those entered by the user sending the message.
  • Ease of implementation. Hook providers are actual MAPI service providers, albeit simple ones, and must follow the guidelines for service providers. However, preprocessors have to be registered by means of a transport provider. If you also happen to have a transport provider that you can modify to register the preprocessor, then creating a preprocessor is probably easier than creating a hook provider. If not, you will have to create a minimal transport provider whose sole job is to register the preprocessor.

For an overview of the process of creating hook providers and preprocessors, see Using Message Filtering to Manage Messages.


Sending Messages using Hook Providers and Preprocessors

The following diagram illustrates the interaction between MAPI components involved in the message sending process.

The steps in this process are:

  1. The message store provider, on behalf of a client application, notifies the MAPI spooler that there is a new message to send.
  2. The MAPI spooler calls each registered preprocessor to act on the message.
  3. The MAPI spooler delivers the message to any transport providers required.
  4. Transport providers transmit the message to the underlying messaging systems.
  5. The MAPI spooler calls each preprocessor's RemovePreprocessInfo function.
  6. The MAPI spooler calls hook providers after all transport providers have completed their work.


Receiving Messages using Hook Providers

The following diagram illustrates the interaction between MAPI components involved in the message receiving process.

The steps in this process are:

  1. The underlying messaging system delivers a message to a transport provider.
  2. The transport provider communicates with the MAPI spooler to get a pointer to a new message object created by the message store provider.
  3. The transport provider writes the inbound message's data to the new message object in the message store.
  4. The MAPI spooler calls all hook providers to operate on the message.
  5. The hook providers communicate with the message store provider to move the message to a different folder, delete it, and so on.


About Hook Providers

Hook providers are MAPI service providers, like message store providers, transport providers, and address book providers. However, hook providers are by far the simplest type of provider to implement. Hook providers are intended to perform sorting and archiving types of tasks with messages. Some typical hook provider tasks are:

  • Sorting incoming messages into folders.
  • Filtering out unwanted incoming messages.
  • Saving copies of outgoing messages in special folders.

Hook providers generally change the relationship between a message and its message store, although they can also change the content of a message.

Hook providers control whether they are called for inbound messages, outbound messages, or both by setting the HOOK_INBOUND and HOOK_OUTBOUND flags in the PR_RESOURCE_FLAGS property of the hook provider's profile section in the MAPISVC.INF file. For more details, see File Format of MAPISVC.INF. In the event that multiple hook providers are being used, the hook providers are called in the order that they are installed into a user's profile.


Hook Provider Entry Points

Hook providers can expose the following entry points in their DLL.

Entry Point | Purpose
HPProviderInit | Called when the provider's DLL is loaded. See HPProviderInit.
ServiceEntry | Entry point called by MAPI from the system's Control Panel application. See MSGSERVICEENTRY.
WizardEntry | Entry point for MAPI configuration wizard. See WIZARDENTRY.

As with all DLLs, the entry points must be called by these names but can map to functions with arbitrary names in your DLL. The HPProviderInit and WizardEntry entry points are required, while the ServiceEntry entry point is optional.


Implementing HPProviderInit for Hook Providers

The HPProviderInit entry point should create a message hook provider object, initialize it, and return a pointer to it in the lppSpoolerHook pointer parameter. Initializing the spooler hook object is usually accomplished by:

  • Storing the MAPI session pointer, instance handle, and memory allocation routine pointers that are passed in by MAPI.
  • Getting the hook provider's configuration information out of its profile section.
  • Verifying that its configuration information is complete and correctly formatted.
  • Connecting to any other MAPI service providers needed — such as store providers — by getting pointers to them from MAPI through the session pointer.
  • Initializing any rules or filters that should be started when the hook provider is loaded.

For more details, see ISpoolerHook : IUnknown.


Implementing ServiceEntry for Hook Providers

The ServiceEntry entry point is called by MAPI when the user configures the provider by means of the system's control panel applet. The ServiceEntry entry point is called after MAPI has gotten new configuration information from the user. The ServiceEntry entry point needs to incorporate that information into the hook provider's profile section.

The ServiceEntry entry point is passed a window handle it can use as the parent window for any user interface it needs to display. Usually the ServiceEntry entry point only needs to display a user interface to confirm or correct any bad configuration information entered by the user. In addition, the ServiceEntry entry point is passed pointers to memory allocation routines and a MAPI support object that can be used to access the hook provider's profile section.

For more details, see MSGSERVICEENTRY, and Supporting Message Service Configuration and File Format of MAPISVC.INF.


Implementing WizardEntry for Hook Providers

The WizardEntry entry point is called by the MAPI Profile Wizard. The WizardEntry entry point is responsible for giving the configuration wizard a pointer to the function to be called to handle window events, and a pointer to the full resource name for the wizard dialog box implemented by the hook provider. The WizardEntry entry point must also support programmatic configuration, that is, it should be possible to call this entry point to configure the hook provider without causing any user interface to be displayed.

Note One of the window events you should expect is WIZ_QUERYNUMPAGES. Your event handling procedure should return the number of pages used to configure your hook provider.

For more information, see Supporting Message Service Configuration, WIZARDENTRY, and SERVICEWIZARDDLGPROC.


Hook Provider Interfaces

Hook providers implement the ISpoolerHook : IUnknown interface. Aside from the QueryInterface, AddRef, and Release methods inherited from the IUnknown interface, ISpoolerHook has only two additional methods to implement: InboundMsgHook and OutboundMsgHook.

The MAPI spooler calls InboundMsgHook after a transport provider receives an inbound message but before the message is delivered to the default receive folder for the message's message class. The MAPI spooler calls OutboundMsgHook after transport providers have delivered the message to any underlying messaging systems.


Implementing the InboundMsgHook and OutboundMsgHook Methods for Hook Providers

You have considerable latitude in how you implement the specifics of the InboundMsgHook and OutboundMsgHook methods. In general, these methods compare one or more properties of the input message against the rules the hook provider implements. Based on these comparisons, the message can be modified, moved to a different message store, moved to a different folder by returning a different folder entry identifier, or marked for deletion by the MAPI spooler by returning a null folder entry identifier.

In addition, these methods return one or both of the flags HOOK_CANCEL and HOOK_DELETE to indicate how the MAPI spooler should react to the InboundMsgHook method's actions. The HOOK_CANCEL flag indicates that no other hook providers should be called for the message. The HOOK_DELETE flag indicates that the MAPI spooler should delete the message; the hook provider should never use calls to the message store provider to delete the message directly but should set the HOOK_DELETE flag and allow the MAPI spooler to delete the message.

Hook providers can create additional messages based on the input message if desired. However, if the hook provider intends for an additional message to be submitted for sending, the message must be created using the default message store provider object provided by the MAPI spooler.

The InboundMsgHook and OutboundMsgHook methods are nearly identical as far as interaction with message objects and message stores. The only architectural difference is that the MAPI spooler calls them at different times. Many hook provider implementations can share substantial portions of code between these methods because they are so similar in function.

See InboundMsgHook and OutboundMsgHook for details on how to treat the flags and folder entry identifier parameters.


Interactions Between Hook Providers and the MAPI Spooler

The interactions between hook providers and the MAPI spooler are fairly simple:

  1. The MAPI spooler receives an inbound or outbound message from a message store or transport provider.
  2. The MAPI spooler calls the hook provider's InboundMsgHook or OutboundMsgHook method, whichever is appropriate.
  3. The hook provider processes the message, optionally returning a different destination folder for the message or returning values that cause the MAPI spooler to delete the message.
  4. The MAPI spooler calls any other hook providers — assuming that HOOK_CANCEL was not returned in step 3 — then delivers the message to its final destination or deletes it as appropriate.


About Preprocessors

Preprocessors are generally implemented along with a transport provider, usually in the same DLL.


Registering a Preprocessor

All preprocessors must be registered by transport providers. The transport provider for a preprocessor registers it along with its other logon processing at the time that the MAPI spooler logs on to the transport provider. To register a preprocessor, the transport provider calls its support object's IMAPISupport::RegisterPreprocessor function. It passes in the name of the DLL in which the preprocessor is implemented and the names of the functions in that DLL that implement the preprocessor.

The transport provider can also control what specific addresses or address types the preprocessor applies to. The preprocessor can apply to specific addresses by giving a specific MAPIUID structure to the RegisterPreprocessor method. The preprocessor can apply to specific address types by giving the string representation of the address type, for example SMTP. A preprocessor can apply to all address types by giving a null or empty string as the address type. The RegisterPreprocessor method must be called once for each MAPIUID or address type.

For more information, see IMAPISupport::RegisterPreprocessor.


Creating a Minimal Transport Provider

Since every preprocessor must be registered by a transport provider, you may need to create a minimal transport provider whose sole task is to register your preprocessor. A minimal transport provider does not advertise any address types to the MAPI spooler, so the MAPI spooler will never call the transport provider to send or receive messages.

To create a minimal transport provider
  1. Create a transport provider with the minimum required interfaces for transport providers. Many of the methods and interfaces used by transport providers can be implemented as stubs that do nothing or return MAPI_E_NO_SUPPORT. The minimal transport provider should initialize as recommended in the topic Required Functionality for Transport Providers. In response to the IXPLogon::AddressTypes call, the transport provider should return a single zero-length string in lpppszAdrTypeArray and NULL in lpppUIDArray.
  2. Create a MAPISVC.INF fragment for the transport provider and the message service that contains it. See Implementing a Message Service.
  3. Optionally, but strongly recommended, create a message service entry point for configuration. See Implementing a Service Provider Entry Point Function.
  4. Optionally, create an online Help file linked to your configuration property pages, wizard pages, or both, providing full details about all configuration options.
  5. Optionally, create a header file for custom programmatic configuration by MAPI clients.
  6. Optionally, create a WizardEntry entry point for interactive configuration by users. See Supporting Message Service Configuration.
  7. Optionally, create a .PRF file detailing configuration properties for the message service.

For more details about transport providers, see Developing a Transport Provider and the quick start topic Creating and Configuring a Profile.


Implementing the PreprocessMessage Function for Preprocessors

The MAPI spooler calls the PreprocessMessage function for messages that meet the preprocessor's criteria for MAPIUID or address type. PreprocessMessage can do several things with the input message:

  • Modify the input message. To modify the input message, the PreprocessMessage function calls the IMAPIProp::OpenProperty method with the MAPI_MODIFY flag for one or more properties of the input message. It then modifies the values of those properties, and calls IMAPIProp::SaveChanges to make the changes permanent.
  • Generate new messages to be sent as well. To generate new messages, the PreprocessMessage function must use its MAPI session pointer to access a message store provider through which it can create new message objects. New messages should be created using the default message store. These new message objects should be passed back to the MAPI spooler in the lpppMessage pointer, which is a pointer to an array of message object pointers. The original input message, however, should never be placed in this array.
  • Prevent the input message from being sent. To prevent the input message from being sent, the PreprocessMessage function must remove all the recipients from the message's recipient list and set the PR_DELETE_AFTER_SUBMIT property on the message. This will prevent the MAPI spooler from submitting the message to any transport providers.
  • Modify the recipient list of a message.

If multiple message preprocessors are being used, the individual PreprocessMessage functions are called in the same order as the transports. This order can be modified programmatically if your preprocessor needs to be called at some specific point in the transport order. See IMAPISession::AdminServices, IMsgServiceAdmin::MsgServiceTransportOrder and IXPLogon::AddressTypes for details.


Implementing the RemovePreprocessInfo Function for Preprocessors

After messages are sent by any transport providers, the MAPI spooler calls each preprocessor's RemovePreprocessInfo function. This gives the preprocessor a chance to undo any changes it made to the input message before the message is passed to any hook providers. For example, a preprocessor for a FAX-based transport can generate a bitmap representation of the input message for sending to receiving fax machines; there will be little reason for that bitmap to be archived by any hook providers, so the RemovePreprocessInfo function can take the bitmap out of the input message before any hook providers process the message.

If multiple message preprocessors are being used, the individual RemovePreprocessInfo functions are called in the opposite order as the PreprocessMessage functions. This is so that RemovePreprocessInfo implementations that depend on positions within the message can locate the information they should remove without interference by the actions of other preprocessors. For example, a preprocessor that adds an automatic closing or signature to a message's PR_BODY or PR_RTF_COMPRESSED properties will probably use a position or offset from the end of the property to locate the information it should remove. If another preprocessor modifies these properties later, then that preprocessor's RemovePreprocessInfo function should undo its actions before the first preprocessor undoes its actions.

Note There is no requirement that the RemovePreprocessInfo function actually undoes the effects of the associated PreprocessMessage function. However, if the RemovePreprocessorInfo does not undo the effects of the PreprocessMessage, then the PreprocessMessage function should take care to make its changes in such a way as to minimize interference with RemovePreprocessInfo implementations that do, or make an effort to inform the user that the transport provider which registers the preprocessor should be installed into the user's profile ahead of other transports.


MAPI Interfaces

The documentation for each interface consists of an introductory section that includes a brief description of the interface's purpose followed by a "Quick Info" table, which contains the following information:

Header file: | The header file where the interface is defined and that must be included when you compile your source code.
Exposed by: | The object that exposes the interface.
Implemented by: | A list of the components that provide an implementation of the interface.
Called by: | A list of the components that typically call the methods of the interface.
Interface identifier: | The interface identifier GUID.
Pointer type: | The pointer type for the object that exposes the interface.
Transaction model: | For interfaces derived from IMAPIProp. If nontransacted, changes take effect immediately; if transacted, changes do not take effect until SaveChanges is called.

Following the "Quick Info" table is another table that lists all the methods of this interface in vtable order. A vtable is an array of function pointers created by the compiler containing one function pointer for each method of a MAPI object. The methods are listed in the same order that they are declared. Methods inherited from other interfaces are not shown in the "Vtable Order" table but can be used in the same way as documented in the interface that defines them.

Following the "Vtable Order" table, the interface's methods are then documented in alphabetical order. For each method, the documentation includes a brief purpose statement for the method and its syntax followed by this information:

Heading | Content
Parameters | A description of each parameter in the method.
Return Values | A description of the unique values that the method can return. These are the values that callers should check for in their code.
Remarks | A description of why and how the method is used.
See Also | Cross-references to other topics in the MAPI Programmer's Reference.


IABContainer : IMAPIContainer

The IABContainer interface provides access to address book containers. MAPI and client applications call the methods of IABContainer to perform name resolution and to create, copy, and delete recipients.

Quick Info

Header file: | MAPIDEFS.H
Exposed by: | Address book container objects
Implemented by: | Address book providers
Called by: | MAPI and client applications
Interface identifier: | IID_IABContainer
Pointer type: | LPABCONT
Transaction model: | Transacted

Vtable Order

CreateEntry | Creates a new entry, which can be a messaging user, a distribution list, or another container.
CopyEntries | Copies one or more entries, typically messaging users or distribution lists.
DeleteEntries | Removes one or more entries, typically messaging users, distribution lists, or other containers.
ResolveNames | Performs name resolution for one or more recipient entries.

Required properties | Access
PR_CONTAINER_FLAGS | Read/write
PR_DISPLAY_NAME | Read/write
PR_ENTRYID | Read-only
PR_OBJECT_TYPE | Read-only
PR_RECORD_KEY | Read-only

Optional properties | Access
PR_CONTAINER_CONTENTS | Read-only
PR_CONTAINER_HIERARCHY | Read-only
PR_DEF_CREATE_DL | Read-only
PR_DEF_CREATE_MAILUSER | Read-only
PR_DISPLAY_TYPE | Read-only

Remarks

The IABContainer interface inherits indirectly from IUnknown through IMAPIContainer and IMAPIProp. Address book providers implement IABContainer.

Any number of messaging user objects, distribution lists, and other address book containers can exist within an address book container. As with any container, clients or service providers can use an address book container to open one of its entries or to retrieve a hierarchy table or contents table. Address book containers also provide name resolution and, depending on the provider, the ability to add, remove, or modify entries.

MAPI defines a special address book container, called the personal address book (PAB), that is meant to hold entries copied from other containers. A PAB is always modifiable. Users typically populate their PAB with entries designating the recipients with which they most frequently communicate. A PAB can also hold one-off addresses — new recipients not yet a part of any address book container.


IABContainer::CopyEntries

The IABContainer::CopyEntries method copies one or more entries, typically messaging users or distribution lists.

Quick Info

See IABContainer : IMAPIContainer.

HRESULT CopyEntries(
  LPENTRYLIST lpEntries,
  ULONG ulUIParam,
  LPMAPIPROGRESS lpProgress,
  ULONG ulFlags
);

Parameters

lpEntries
[in] Pointer to an array of ENTRYLIST structures containing the entry identifiers of the entries to copy.
ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays. The ulUIParam parameter must be zero if the AB_NO_DIALOG flag is set in the ulFlags parameter.
lpProgress
[in] Pointer to a progress object for displaying a progress indicator or NULL. If lpProgress is NULL, a progress indicator should be displayed using the progress object supplied by MAPI through the IMAPISupport::DoProgressDialog method. The lpProgress parameter is ignored if AB_NO_DIALOG is set in ulFlags.
ulFlags
[in] Bitmask of flags that controls how the copy operation is performed. The following flags can be set:
AB_NO_DIALOG
Suppresses display of a progress indicator. If this flag is not set, a progress indicator is displayed.
CREATE_CHECK_DUP_LOOSE
Suggests that a loose level of duplicate entry checking should be performed. The implementation of loose duplicate entry checking is provider-specific. For example, a provider can define a loose match as any two entries having the same display name.
CREATE_CHECK_DUP_STRICT
Suggests that a strict level of duplicate entry checking should be performed. The implementation of strict duplicate entry checking is provider-specific. For example, a provider can define a strict match as any two entries having both the same display name and messaging address.
CREATE_REPLACE
A new entry should replace an existing one if it is determined that the two are duplicates.

Return Values

S_OK
The copy operation succeeded.
MAPI_W_PARTIAL_COMPLETION
The copy operation succeeded overall, but one or more of the recipients could not be copied. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IABContainer::CopyEntries method copies recipients from the same container or a different container. A call to CopyEntries is functionally equivalent to making the following three calls for each recipient to be copied:

  1. IABContainer::CreateEntry to create the new recipient.
  2. The new recipient's IMAPIProp::SaveChanges method to perform a save.
  3. The new recipient's IUnknown::Release method to release the container's reference.

The personal address book (PAB) supplied by MAPI does not support the CREATE_REPLACE flag. For duplicate entry checking, the PAB defines "loose" to mean that two entries are duplicates if their original display names are equal and "strict" to mean that two entries are duplicates if both their original display names and search keys are equal. In the PAB, the original display name is defined as the transmittable display name, if available. Otherwise, it is simply the display name. Combined with the PR_SEARCH_KEY property, these criteria usually eliminate duplicates in most applications whether automated or user driven.

Notes to Implementers

All containers that support IABContainer::CopyEntries must be modifiable. Set your container's AB_MODIFIABLE flag in its PR_CONTAINER_FLAGS property to indicate that it is modifiable.

You must support all of the ulFlags flags; however, the interpretation and use of these flags is implementation-specific. That is, you can determine what the semantics of CREATE_CHECK_DUP_LOOSE and CREATE_CHECK_DUP_STRICT mean within the context of your implementation. If you cannot or do not determine whether an entry is a duplicate, always allow the entry to be copied.

If CREATE_REPLACE is set, always copy the entry regardless of whether CREATE_CHECK_DUP_LOOSE or CREATE_CHECK_DUP_STRICT is set and whether or not the entry is a duplicate.

If CREATE_REPLACE is not set and CREATE_CHECK_DUP_STRICT is set, check for duplicates. If any entries are determined to be duplicates, do not copy the entry.

You do not need to support the CREATE_REPLACE flag; not supporting CREATE_REPLACE means that you can ignore it and always perform a copy.

Return the warning MAPI_W_PARTIAL_COMPLETION only if a nonduplicate entry cannot be copied.

Notes to Callers

Use the CREATE_CHECK_DUP_LOOSE and CREATE_CHECK_DUP_STRICT flags to suggest to the provider how you would like the container to perform duplicate entry checking. If you need to have an entry added regardless of whether or not it is a duplicate, either do not set either of these flags or set the CREATE_REPLACE flag. CREATE_REPLACE indicates that you do not care if an entry is a duplication; you always want it to replace the original entry.

See Also

ENTRYLIST, IABContainer::CreateEntry, IMAPIProgress : IUnknown, IMAPIProp::SaveChanges


IABContainer::CreateEntry

The IABContainer::CreateEntry method creates a new entry, which can be a messaging user, a distribution list, or another container.

Quick Info

See IABContainer : IMAPIContainer.

HRESULT CreateEntry(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  ULONG ulCreateFlags,
  LPMAPIPROP FAR * lppMAPIPropEntry
);

Parameters

cbEntryID
[in] Count of the bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of a template for creating new entries of a particular type.
ulCreateFlags
[in] Bitmask of flags that controls how entry creation is performed. The following flags can be set:
CREATE_CHECK_DUP_LOOSE
Suggests that a loose level of duplicate entry checking should be performed. The implementation of loose duplicate entry checking is provider-specific. For example, a provider can define a loose match as any two entries having the same display name.
CREATE_CHECK_DUP_STRICT
Suggests that a strict level of duplicate entry checking should be performed. The implementation of strict duplicate entry checking is provider-specific. For example, a provider can define a strict match as any two entries having both the same display name and messaging address.
CREATE_REPLACE
A new entry should replace an existing one if it is determined that the two are duplicates.
lppMAPIPropEntry
[out] Pointer to a pointer to the newly created entry.

Return Values

S_OK
The new entry was successfully created.

Remarks

The IABContainer::CreateEntry method creates a new entry of a particular type in the container, returning a pointer to an interface implementation for further access to the entry. The new entry is created using a template that has been selected from the container's list of available templates published in its one-off table. Callers access a container's one-off table by calling its IMAPIProp::OpenProperty method and requesting the PR_CREATE_TEMPLATES property.

Notes to Implementers

All containers that support IABContainer::CreateEntry must be modifiable. Set your container's AB_MODIFIABLE flag in its PR_CONTAINER_FLAGS property to indicate that it is modifiable.

Although the MAPI personal address book does not support the CREATE_REPLACE flag, MAPI recommends that you support all of the ulFlags flags. However, the interpretation and use of these flags is implementation-specific. That is, you can determine what the semantics of CREATE_CHECK_DUP_LOOSE and CREATE_CHECK_DUP_STRICT mean within the context of your implementation. If you cannot or do not determine whether an entry is a duplicate, always allow the entry to be created.

Some providers implement strict entry checking by matching the display name, messaging address, and search key in an entry; other providers limit the match to display name and address. Loose entry checking is often implemented by checking the display name only.

Notes to Host Provider Implementers

If your container can create entries from the templates of other providers, your implementation of CreateEntry should provide storage for some or all of the properties associated with the created entries. For example, if you provide storage for an entry's PR_DETAILS_TABLE property, you will be able to generate its details dialog box without having to depend on the foreign provider.

If your container can create entries that support the PR_TEMPLATEID property, your implementation of CreateEntry must:

  1. Call IMAPISupport::OpenTemplateID. OpenTemplateID allows the foreign provider's code for the entry to bind to the new entry being created. Foreign providers support this binding process to maintain control over entries created from their templates into the containers of host providers.
  2. Perform any necessary initialization and populate the new object with all of the properties from the entry in the foreign provider — the object returned in the lppMAPIPropNew parameter from OpenTemplateID.

If OpenTemplateID succeeds, copy the properties to the bound interface — the implementation pointed to by the lppMAPIPropNew parameter — rather than directly to the implementation pointed to by the lpMAPIPropData parameter. Initialize the new entry for offline use as you would any other entry from a foreign provider.

If OpenTemplateID returns an error, CreateEntry should fail. Do not allow the entry to be created. Because the foreign provider can make assumptions about the data in your provider, do not create an entry with a template identifier that has not been successfully bound to the foreign provider.

Notes to Callers

When CreateEntry returns, you may or may not be able to access the entry identifier for the new entry immediately. Some address book providers do not make it accessible until after you have called the new entry's IMAPIProp::SaveChanges method.

Although duplicate checking flags are passed as parameters to CreateEntry, the duplicate checking operation does not occur until SaveChanges is called. Therefore, related errors such as MAPI_E_COLLISION, indicating that an attempt was made to create an already existing entry, are returned by SaveChanges rather than CreateEntry.

See Also

IABContainer::CopyEntries, IMAPIProp::OpenProperty, IMAPIProp::SaveChanges, PR_CREATE_TEMPLATES


IABContainer::DeleteEntries

The IABContainer::DeleteEntries method removes one or more entries, typically messaging users, distribution lists, or other containers.

Quick Info

See IABContainer : IMAPIContainer.

HRESULT DeleteEntries(
  LPENTRYLIST lpEntries,
  ULONG ulFlags
);

Parameters

lpEntries
[in] Pointer to an array of ENTRYLIST structures containing entry identifiers representing the entries being deleted.
ulFlags
Reserved; must be zero.

Return Values

S_OK
The specified entries have been successfully deleted.
MAPI_W_PARTIAL_COMPLETION
The call succeeded, but one or more of the entries could not be deleted. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.


IABContainer::ResolveNames

The IABContainer::ResolveNames method performs name resolution for one or more recipient entries.

Quick Info

See IABContainer : IMAPIContainer.

HRESULT ResolveNames(
  LPSPropTagArray lpPropTagArray,
  ULONG ulFlags,
  LPADRLIST lpAdrList,
  LPFlagList lpFlagList
);

Parameters

lpPropTagArray
[in] Pointer to an SPropTagArray structure containing an array of property tags describing the properties to be included in the ADRLIST structure returned by the provider. To request the provider's default set of properties, pass NULL in the lpPropTagArray parameter.
ulFlags
[in] Bitmask of flags that controls the type of the text in the returned strings. The following flag can be set:
MAPI_UNICODE
The returned string properties are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lpAdrList
[in, out] On input, pointer to an ADRLIST structure containing the list of recipients to be resolved. On output, pointer to an ADRLIST structure containing the resolved names.
lpFlagList
[in, out] Pointer to an array of flags; each flag corresponding to an ADRENTRY structure in the lpAdrList parameter, that provides the status of the name resolution operation for the recipient. The flags in the lpFlagList parameter are in the same order as the entries in lpAdrList. The following flags can be set:
MAPI_AMBIGUOUS
The corresponding recipient has been resolved, but not to a unique entry identifier. Other containers should not try to resolve this recipient.
MAPI_RESOLVED
The corresponding recipient has been resolved to a unique entry identifier. Other containers should not try to resolve this recipient.
MAPI_UNRESOLVED
The corresponding entry has not been resolved. Other containers should try to resolve this recipient.

Return Values

S_OK
The name resolution process was successful.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.
MAPI_E_NO_SUPPORT
The address book provider does not support bulk name resolution using this method.

Remarks

The IABContainer::ResolveNames method attempts to match unresolved recipients from the array of entries in the lpAdrList parameter to recipients in this address book container. An unresolved recipient typically only has the PR_DISPLAY_NAME property and possibly a few other properties. An unresolved recipient does not have the PR_ENTRYID property, and its corresponding flag in the lpFlagList parameter is set to MAPI_UNRESOLVED. Conversely, a resolved recipient always has at least the PR_ENTRYID property plus several other properties such as PR_EMAIL_ADDRESS, PR_DISPLAY_NAME, and PR_ADDRTYPE.

The name resolution typically begins when a client calls IAddrBook::ResolveName. MAPI responds by calling the IABContainer::ResolveNames method of each address book container that is included in the address book search path — the PR_AB_SEARCH_PATH property. The entries in the lpAdrList parameter include recipients already resolved by containers that have already been called because they appear earlier in the search path and unresolved recipients.

Each container attempts to resolve the unresolved entries by matching the display name of the recipient with the display name of one of its entries. When a unique match is found, ResolveNames adds the PR_ENTRYID property and other properties included in the lpPropTagArray parameter to the corresponding entry in the outgoing ADRLIST structure and sets the entry in the lpFlagList parameter to MAPI_RESOLVED. The entry identifier stored in the PR_ENTRYID property can be short-term or long-term.

After all of the containers in the search path have attempted the name resolution process, MAPI launches a dialog box, if possible, to prompt the user for help in resolving any remaining conflicts.

Clients can also use the returned ADRLIST structure in calls to the IMessage::ModifyRecipients method.

Notes to Implementers

You are not required to support name resolution with the IABContainer::ResolveNames method. Instead, or in addition, you can support it with the PR_ANR property restriction. If you choose to rely on the PR_ANR restriction for name resolution, you can return MAPI_E_NO_SUPPORT from IABContainer::ResolveNames. For more information, see Implementing Name Resolution.

Set a recipient's flag entry in the lpFlagList parameter to MAPI_UNRESOLVED if the recipient does not match any of the container's recipients.

When a recipient matches multiple recipients, set its flag to MAPI_AMBIGUOUS and do not alter its ADRENTRY structure.

MAPI requires certain properties on recipients that are included in a message's recipient list. You can include them in the ADRENTRY structure as part of the name resolution process or wait for MAPI to request them during the processing of IAddrBook::PrepareRecips and IMAPISupport::ExpandRecips. Eliminate these extra calls and improve performance by including the following properties in the ADRENTRY structures of all resolved recipients:

PR_ADDRTYPE

PR_DISPLAY_NAME

PR_EMAIL_ADDRESS

PR_ENTRYID

PR_OBJECT_TYPE

PR_SEARCH_KEY

PR_TRANSMITTABLE_DISPLAY_NAME

If some of the properties in the lpPropTagArray parameter are unavailable — typically because the container entry does not support them and they are not included in the recipient's ADRENTRY member in the ADRLIST structure — set the property type of each unavailable property to PT_ERROR.

Do not remove any properties from a resolved recipient's ADRENTRY structure.

If you need to replace rather than modify an ADRENTRY structure, free the original ADRENTRY structure first by calling the MAPIFreeBuffer function and then allocate the replacement ADRENTRY structure with MAPIAllocateBuffer.

See Also

ADRENTRY, ADRLIST, IAddrBook::PrepareRecips, IAddrBook::ResolveName, IMAPISupport::ExpandRecips, IMessage::ModifyRecipients, PR_ANR, SPropertyRestriction


IABLogon : IUnknown

The IABLogon interface is used to access resources in an address book provider.

Quick Info

Header file: | MAPISPI.H
Exposed by: | Address book logon objects
Implemented by: | Address book providers
Called by: | MAPI
Interface identifier: | IID_IABLogon
Pointer type: | LPABLOGON

Vtable Order

GetLastError | Returns a MAPIERROR structure containing information about the previous address book provider error.
Logoff | Initiates the logoff process.
OpenEntry | Opens a container, messaging user, or distribution list and returns a pointer to an interface implementation to provide further access.
CompareEntryIDs | Compares two entry identifiers to determine if they refer to the same object.
Advise | Registers to receive notification of specified events affecting a container, messaging user, or distribution list.
Unadvise | Cancels the sending of notifications previously set up with a call to the IABLogon::Advise method.
OpenStatusEntry | Opens the provider's status object.
OpenTemplateID | Opens a recipient entry that has data residing in a host address book provider.
GetOneOffTable | Returns a table of one-off templates for creating recipients to be added to the recipient list of an outgoing message.
PrepareRecips | Prepares a recipient list for later use by the messaging system.

Remarks

For general information about the methods of IABLogon, see Implementing Service Provider Logon.


IABLogon::Advise

The IABLogon::Advise method registers to receive notification of specified events affecting a container, messaging user, or distribution list.

Quick Info

See IABLogon : IUnknown.

HRESULT Advise(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  ULONG ulEventMask,
  LPMAPIADVISESINK lpAdviseSink,
  ULONG FAR * lpulConnection
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the object about which notifications should be generated.
ulEventMask
[in] A mask of values indicating the types of notification events that the caller is interested in and should be included in the registration. There is a corresponding NOTIFICATION structure associated with each type of event that holds information about the event.

The following table lists the valid values for the ulEventMask parameter and the structures associated with each value.
Notification event type Corresponding NOTIFICATION structure
fnevCriticalError
 ERROR_NOTIFICATION
fnevObjectCreated
 OBJECT_NOTIFICATION
fnevObjectDeleted
 OBJECT_NOTIFICATION
fnevObjectModified
 OBJECT_NOTIFICATION
fnevObjectCopied
 OBJECT_NOTIFICATION
fnevObjectMoved
 OBJECT_NOTIFICATION

lpAdviseSink
[in] Pointer to an advise sink object to receive the subsequent notifications.
lpulConnection
[out] Pointer to a nonzero value that represents the notification registration.

Return Values

S_OK
The notification registration was successful.
MAPI_E_INVALID_ENTRYID
The entry identifier passed in lpEntryID is not in the appropriate format.
MAPI_E_NO_SUPPORT
The address book provider does not support notification, possibly because it does not allow changes to be made to its objects.
MAPI_E_UNKNOWN_ENTRYID
The address book provider cannot handle the entry identifier passed in lpEntryID.

Remarks

Address book providers implement the IABLogon::Advise method to register the caller to be notified when a change occurs to an object in one of their containers. Callers can register for notifications on messaging users, distribution lists, or entire containers.

Clients typically call IAddrBook::Advise to register for address book notifications. MAPI then calls the IABLogon::Advise method of the address book provider that is responsible for the object represented by the entry identifier in lpEntryID.

When a change occurs to the indicated object of the type represented in ulEventMask, a call is made to the OnNotify method of the advise sink pointed to by lpAdviseSink. Data passed in the notification structure to the OnNotify routine describes the event.

Notes to Implementers

You can support notification with or without help from MAPI. MAPI has three support object methods for helping service providers implement notification:

IMAPISupport::Subscribe

IMAPISupport::Unsubscribe

IMAPISupport::Notify

If you elect to use the MAPI support methods, call Subscribe when your Advise method is called and release the lpAdviseSink pointer.

If you elect to support notification yourself, call the IUnknown::AddRef method of the advise sink represented by the lpAdviseSink parameter to keep a copy of this pointer. Maintain this copy until your IABLogon::Unadvise method is called to cancel the registration.

Regardless of how you support notification, assign a nonzero connection number to the notification registration and return it in the lpulConnection parameter. Do not release this connection number until Unadvise has been called.

Notes to Callers

The advise sink pointer that you pass in the lpAdviseSink parameter to Advise can point to an object that you have created or that MAPI has created through the HrThisThreadAdviseSink function. You might want to use HrThisThreadAdviseSink if you support multiple threads of execution and want to ensure that subsequent calls to your OnNotify method occur at an appropriate time on an appropriate thread.

Be prepared for your advise sink object to be released any time after your call to Advise and before your call to Unadvise. MAPI recommends that you release your advise sink object after Advise returns, unless you have a specific long-term use for it.

For more information on the notification process, see Event Notification in MAPI. For information about using the IMAPISupport methods to support notification, see Supporting Event Notification. For more information about multithreading and MAPI, see Threading in MAPI.

See Also

HrThisThreadAdviseSink, IABLogon::Unadvise, IMAPIAdviseSink::OnNotify, NOTIFICATION


IABLogon::CompareEntryIDs

The IABLogon::CompareEntryIDs method compares two entry identifiers to determine if they refer to the same object.

Quick Info

See IABLogon : IUnknown.

HRESULT CompareEntryIDs(
  ULONG cbEntryID1,
  LPENTRYID lpEntryID1,
  ULONG cbEntryID2,
  LPENTRYID lpEntryID2,
  ULONG ulFlags,
  ULONG FAR * lpulResult
);

Parameters

cbEntryID1
[in] Count of bytes in the entry identifier pointed to by the lpEntryID1 parameter.
lpEntryID1
[in] Pointer to the first entry identifier to be compared.
cbEntryID2
[in] Count of bytes in the entry identifier pointed to by the lpEntryID2 parameter.
lpEntryID2
[in] Pointer to the second entry identifier to be compared.
ulFlags
Reserved; must be zero.
lpulResult
[out] Pointer to the returned result of the comparison. The contents of lpulResult is TRUE if the two entry identifiers refer to the same object, and FALSE otherwise.

Return Values

S_OK
The entry identifiers were successfully compared.
MAPI_E_INVALID_ENTRYID
One or both of the entry identifiers do not belong to the address book provider.

Remarks

Address book providers implement the IABLogon::CompareEntryIDs method to compare two entry identifiers to determine whether they refer to the same object.

CompareEntryIDs is useful because an object can have more than one valid entry identifier; such a situation can occur, for example, when trying to compare a short-term entry identifier with a long-term entry identifier.

For more information about creating entry identifiers, see Entry Identifiers.


IABLogon::GetLastError

The IABLogon::GetLastError method returns a MAPIERROR structure containing information about the previous address book provider error.

Quick Info

See IABLogon : IUnknown.

HRESULT GetLastError(
  HRESULT hResult,
  ULONG ulFlags,
  LPMAPIERROR FAR * lppMAPIError
);

Parameters

hResult
[in] HRESULT data type containing the error value generated in the previous method call.
ulFlags
[in] Bitmask of flags that controls the type of the returned strings. The following flag can be set:
MAPI_UNICODE
The strings in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppMAPIError
[out] Pointer to a pointer to a MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if the provider cannot supply a MAPIERROR structure with appropriate information.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the address book provider does not support Unicode, or MAPI_UNICODE was not set and the address book provider only supports Unicode.

Remarks

Address book providers implement the IABLogon::GetLastError method to supply information about a prior method call that failed. Callers can provide their users with detailed information about the error by including the data from the MAPIERROR structure in a dialog box.

Notes to Callers

You can make use of the MAPIERROR structure pointed to by the lppMAPIError parameter — if the address book provider supplies one — only if GetLastError returns S_OK. Sometimes the address book provider cannot determine what the last error was or has nothing more to report about the error. In this situation, the address book provider returns a pointer to NULL in lppMAPIError instead.

For more information about the GetLastError method, see Using Extended Errors.

See Also

MAPIERROR, MAPIFreeBuffer


IABLogon::GetOneOffTable

The IABLogon::GetOneOffTable method returns a table of one-off templates for creating recipients to be added to the recipient list of an outgoing message.

Quick Info

See IABLogon : IUnknown.

HRESULT GetOneOffTable(
  ULONG ulFlags,
  LPMAPITABLE FAR * lppTable
);

Parameters

ulFlags
[in] Bitmask of flags that controls the type of string columns included in the table. The following flag can be set:
MAPI_UNICODE
The string columns are in Unicode format. If the MAPI_UNICODE flag is not set, the string columns are in ANSI format.
lppTable
[out] Pointer to a pointer to the one-off table.

Return Values

S_OK
The one-off table was successfully retrieved.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the address book provider does not support Unicode, or MAPI_UNICODE was not set and the address book provider only supports Unicode.
MAPI_E_NO_SUPPORT
The address book provider does not supply any one-off templates.

Remarks

MAPI calls the IABLogon::GetOneOffTable method to make available one-off templates for creating recipients. The new recipients are added to the recipient list of an outgoing message. Address book providers should support notification on their one-off table to inform MAPI of template modifications. MAPI keeps the one-off table open to enable dynamic updating.

Address book providers can also support a one-off table for each of their containers. Callers retrieve this one-off table by calling the container's IMAPIProp::OpenProperty method and requesting the PR_CREATE_TEMPLATES property. The templates available through this table are used to add recipients to the container. For a discussion of the differences between the two types of one-off tables, see Implementing One-Off Tables.

For a list of the required columns in an address book provider's one-off table, see One-Off Tables.

See Also

IABContainer::CreateEntry, IAddrBook::NewEntry, IMAPISupport::GetOneOffTable


IABLogon::Logoff

The IABLogon::Logoff method initiates the logoff process.

Quick Info

See IABLogon : IUnknown.

HRESULT Logoff(
  ULONG ulFlags
);

Parameters

ulFlags
Reserved; must be zero.

Return Value

S_OK
The logoff process was successfully initiated.

Remarks

The logoff process is typically started when a client calls IMAPISession::Logoff to end a session. MAPI then calls each address book provider's IABLogon::Logoff method to start the logoff process.

IABLogon::Logoff:

  • Releases all open objects, such as any subobjects or the status object.
  • Releases the provider's support object.

For more information about the logoff process of address book providers, see Shutting Down a Service Provider.

See Also

IABProvider::Logon


IABLogon::OpenEntry

The IABLogon::OpenEntry method opens a container, messaging user, or distribution list and returns a pointer to an interface implementation to provide further access.

Quick Info

See IABLogon : IUnknown.

HRESULT OpenEntry(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  LPCIID lpInterface,
  ULONG ulFlags,
  ULONG FAR * lpulObjType,
  LPUNKNOWN FAR * lppUnk
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the container, messaging user, or distribution list to open.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the open object. Passing NULL results in the identifier for the object's standard interface being returned. For containers, the standard interface is IABContainer. The standard interfaces for address book objects are IDistList for a distribution list and IMailUser for a messaging user.
ulFlags
[in] Bitmask of flags that controls how the object is opened. The following flags can be set:
MAPI_BEST_ACCESS
Requests that the object be opened with the maximum network permissions allowed for the user and the maximum client application access. For example, if the client has read/write access, the object should be opened with read/write access; if the client has read-only access, the object should be opened with read-only access.
MAPI_DEFERRED_ERRORS
Allows OpenEntry to return successfully, possibly before the object is fully accessible to the calling client. If the object is not accessible, making a subsequent object call can result in an error.
MAPI_MODIFY
Requests read/write access. By default, objects are opened with read-only access, and clients should not work on the assumption that read/write access has been granted.
lpulObjType
[out] Pointer to the type of the opened object.
lppUnk
[out] Pointer to a pointer to the opened object.

Return Values

S_OK
The object was successfully opened.
MAPI_E_NO_ACCESS
Either the user has insufficient permissions to open the object or an attempt was made to open a read-only object with read/write access.
MAPI_E_NOT_FOUND
The entry identifier specified by lpEntryID does not represent an object.
MAPI_E_UNKNOWN_ENTRYID
The entry identifier in the lpEntryID parameter is not of a format recognized by the address book provider.

Remarks

MAPI calls the IABLogon::OpenEntry method to open a container, messaging user, or distribution list.

Notes to Implementers

Before MAPI calls your IABLogon::OpenEntry method, it determines that the entry identifier in the lpEntryID parameter belongs to you and not to another provider. MAPI does this by matching the MAPIUID structure in the entry identifier with the MAPIUID that you registered by calling IMAPISupport::SetProviderUID at start up.

Open the object as read-only, unless the MAPI_MODIFY or MAPI_BEST_ACCESS flag is set in the ulFlags parameter. If you do not allow modification for the object requested, do not open the object at all and return MAPI_E_NO_ACCESS.

If MAPI passes NULL for lpEntryID, open the root container in your container hierarchy.

The object that you are being asked to open might be an object copied from another provider. In this case, it will support the PR_TEMPLATEID property. If the object does support this property, call IMAPISupport::OpenTemplateID to bind to code for this entry in the foreign provider. Pass PR_TEMPLATEID in the lpTemplateID parameter and zero in the ulTemplateFlags parameter. IMAPISupport::OpenTemplateID passes this information to the foreign provider in a call to the foreign provider's IABLogon::OpenTemplateID method. If IMAPISupport::OpenTemplateID returns an error, usually because the foreign provider is unavailable or not included in the profile, try to continue by treating the unbound entry as read-only. For more information about opening foreign address book entries, see Acting as a Host Address Book Provider.


IABLogon::OpenStatusEntry

The IABLogon::OpenStatusEntry method opens the provider's status object.

Quick Info

See IABLogon : IUnknown.

HRESULT OpenStatusEntry(
  LPCIID lpInterface,
  ULONG ulFlags,
  ULONG FAR * lpulObjType,
  LPMAPISTATUS FAR * lppMAPIStatus
);

Parameters

lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the status object. Passing NULL results in the object's standard interface being returned, which is IMAPIStatus.
ulFlags
[in] Bitmask of flags that controls how the status object is opened. The following flag can be set:
MAPI_MODIFY
Requests read/write access. By default, objects are opened with read-only access, and callers should not work on the assumption that read/write access has been granted.
lpulObjType
[out] Pointer to the type of the opened object.
lppEntry
[out] Pointer to a pointer to the opened object.

Return Value

S_OK
The call succeeded and the status object has been opened.

Remarks

Address book providers implement the IABLogon::OpenStatusEntry method to grant access to their status object. All address book providers are required to implement a status object that supports at a minimum the IMAPIStatus::ValidateState method. For more information, see Implementing a Status Object.

See Also

IMAPIStatus : IMAPIProp, IMAPIStatus::SettingsDialog, IMAPIStatus::ValidateState


IABLogon::OpenTemplateID

The IABLogon::OpenTemplateID method opens a recipient entry that has data residing in a host address book provider.

Quick Info

See IABLogon : IUnknown.

HRESULT OpenTemplateID(
  ULONG cbTemplateID,
  LPENTRYID lpTemplateID,
  ULONG ulTemplateFlags,
  LPMAPIPROP lpMAPIPropData,
  LPCIID lpInterface,
  LPMAPIPROP FAR * lppMAPIPropNew,
  LPMAPIPROP lpMAPIPropSibling
);

Parameters

cbTemplateID
[in] Count of bytes in the template identifier pointed to by the lpTemplateID parameter.
lpTemplateID
[in] Pointer to the template identifier, or PR_TEMPLATEID property, of the recipient entry to be opened.
ulTemplateFlags
[in] Bitmask of flags used to indicate how to open the entry represented by the template identifier. The following flag can be set:
FILL_ENTRY
The host provider is creating a new entry in its container based on the entry represented by the template identifier. OpenTemplateID should either perform specific initialization of the host provider's entry, using the IMAPIProp implementation in the lpMAPIPropData parameter, or return a custom IMAPIProp implementation in the lppMAPIPropNew parameter.
lpMAPIPropData
[in] Pointer to the host provider's property object— an implementation of an interface derived from IMAPIProp.
lpInterface
[in] Pointer to the interface identifier (IID) representing the type of interface pointer to be returned in the lppMAPIPropNew parameter. Passing NULL results in the return of the standard messaging user interface, IMailUser.
lppMAPIPropNew
[out] Pointer to the bound property object —an implementation of an interface derived from IMAPIProp.
lpMAPIPropSibling
Reserved; must be NULL.

Return Values

S_OK
The appropriate code was successfully bound to related data in the host provider.
MAPI_E_UNKNOWN_ENTRYID
The template identifier passed in the lpTemplateID parameter is not recognized by the address book provider.

Remarks

The IABLogon::OpenTemplateID method is implemented only by address book providers that need to maintain control over copies of their entries that exist in the containers of host providers. Providers that implement OpenTemplateID are known as foreign address book providers. Host providers call IMAPISupport::OpenTemplateID to create a copied entry or open the copied entry, and MAPI passes on the call to IABLogon::OpenTemplateID. IABLogon::OpenTemplateID opens the entry and binds the code that controls it to data in the host provider.

Rather than use an entry identifier, OpenTemplateID uses another property, the entry's template identifier — PR_TEMPLATEID. Template identifiers should be supported for entries whose code will need to be bound to data in a host provider.

Some examples of when an address book provider should implement IABLogon::OpenTemplateID are:

  • To periodically update the data for a copied entry so that it stays synchronized with the original.
  • To implement functionality that the host provider cannot implement, such as dynamically populating a list box that appears in the entry's details table from data on a server.
  • To control the interaction between properties in the host provider's entry and the original entry, such as computing PR_EMAIL_ADDRESS from edit controls in the details display that hold various components of the address.

Notes to Implementers

When a host provider copies or creates an entry from your provider and you supply a property object implementation through IABLogon::OpenTemplateID, you handle most of the calls to maintain the entry. However, because it is up to the host provider to forward these calls to you, the host provider can intercept any call and perform custom processing before forwarding the call.

You should adhere to the following guidelines in your property object implementations:

  • When IMAPIProp::GetProps is called, determine if the request is for a computed property and if it is, handle it. Transfer all requests for noncomputed properties to the host provider.
  • When IMAPIProp::OpenProperty is called to open any table except the details display table, handle the request. Most tables cannot be copied accurately to the host provider. You must generate the IMAPITable implementation for these requested tables. The details table — PR_DETAILS_TABLE property — must be copied to the host provider, thereby allowing this provider to generate the table locally. You might want to wrap the display table implementation to generate display table notifications.
  • When IMAPIProp::SetProps is called, the host provider can validate the data before allowing you to set the properties. You can verify that all of the necessary properties were set or computed. If an error is detected, return the appropriate error value and, if possible, a further explanation through IMAPIProp::GetLastError.
  • When IMAPIProp::SaveChanges is called, the host provider might want to perform processing before you save the entry. You should save any data that is affected by the changed properties, such as a new address, in the host provider's entry.

In general, make your implementation of the entry that you pass back to the host provider intercept all of the methods to perform context-specific manipulation of the relevant properties. If the FILL_ENTRY flag is passed in the ulFlags parameter, set all properties for the entry.

If you return a new property object in the lppMAPIPropNew parameter, call the IUnknown::AddRef method of the host provider's property object to maintain a reference. All calls through the bound object — the IMAPIProp implementation returned in lppMAPIPropNew — should be routed to their corresponding method in the host property object after they are dealt with by the bound object.

The property identifiers of any named properties that are passed through your bound property object are in your provider's identifier name space. Your implementation of the IMAPIProp::GetNamesFromIDs method should determine the names of the properties so that it can perform any template-specific tasks. Similarly, properties that your provider passes on to the host provider must also be in your name space. For example, if you set a named property in OpenTemplateID, you should use one of your identifiers for the name, creating it if necessary by calling GetIDsFromNames.

If you do not recognize the entry identifier passed in lpTemplateID, return MAPI_E_UNKNOWN_ENTRYID.

For more information on working with address book template identifiers, see Acting as a Foreign Address Book Provider.

See Also

IMAPISupport::OpenTemplateID, IPropData : IMAPIProp, PR_TEMPLATEID


IABLogon::PrepareRecips

The IABLogon::PrepareRecips method prepares a recipient list for later use by the messaging system.

Quick Info

See IABLogon : IUnknown.

HRESULT PrepareRecips(
  ULONG ulFlags,
  LPSPropTagArray lpPropTagArray,
  LPADRLIST lpRecipList
);

Parameters

ulFlags
Reserved; must be zero.
lpPropTagArray
[in] Pointer to an SPropTagArray structure containing an array of property tags indicating the properties that require updating, if any. The lpPropTagArray parameter can be NULL.
lpRecipList
[in] Pointer to an ADRLIST structure holding the recipient list.

Return Values

S_OK
The recipient list was successfully prepared.
MAPI_E_NOT_FOUND
One or more of the recipients in the lpRecipList parameter does not exist.

Remarks

A client calls the MAPI IAddrBook::PrepareRecips method to modify or rearrange a set of properties for one or more recipients. The recipients may or may not be part of the recipient list of an outgoing message. MAPI transfers this call to an address book provider's IABLogon::PrepareRecips method.

PrepareRecips performs four main tasks:

  • Ensures that all recipients in the address list pointed to by lpRecipList have a long-term entry identifier.
  • Ensures that all recipients have the properties specified in the property tag array pointed to by lpPropTagArray.
  • Ensures that the properties from the property tag array appear before any other properties that existed prior to the call.
  • Ensures that the order of the properties in each recipient's ADRENTRY structure in the ADRLIST structure is the same as in the property tag array.

The ADRLIST structure in the lpRecipList parameter contains one ADRENTRY structure for each recipient. Each ADRENTRY structure contains an array of SPropValue structures to describe the recipient's properties. When PrepareRecips returns, the SPropValue structure array for each recipient includes the properties from the lpPropTagArray followed by the other properties for the recipient.

Notes to Implementers

Implementing PrepareRecips involves placing properties in a specific order, retrieving property values, and converting short-term entry identifiers to long-term entry identifiers. The properties that are included in the lpPropTagArray parameter should appear at the beginning of the property value array associated with each recipient's ADRENTRY structure in the lpRecipList parameter. If values for these properties do not exist, open the associated messaging user or distribution list by using its entry identifier and retrieve the missing property values.

Allocate each SPropValue structure passed in lpPropTagArray separately so that the structures can be freed individually. If you must allocate additional space for any SPropValue structure — for example, to store the data for a string property — use MAPIAllocateBuffer to allocate additional space for the full property tag array. Use the MAPIFreeBuffer function to free the original property tag array and then use MAPIAllocateMore to allocate any additional memory required.

To implement IABLogon::PrepareRecips
  1. Check for entries in the lpPropTagArray parameter. If the property tag array is empty, there is no work to do. Return with a success value.
  2. Process each recipient in the lpRecipList parameter. There is one ADRENTRY structure member for each recipient in the list. Ignore the following types of recipients:
    • Recipients without an entry identifier in the rgPropVals member of their ADRENTRY structure, that is, unresolved recipients.
    • Recipients with an entry identifier that does not belong to your provider. These recipients will be passed on to another address book provider.
  3. Open the recipient and retrieve the properties already set for the recipient.
  4. Merge the property value array specified in the lpPropTagArray with the array of properties returned from GetProps. If the same property exists in both property arrays, use the value from lpPropTagArray.
  5. If the lpPropTagArray property value array is big enough to hold all of the necessary properties, just replace it with the merged array. If the lpPropTagArray property value array is not big enough, replace it with a newly allocated array. Make sure the new array has an updated value in each of its cValues members.
  6. If you do not recognize one or more of the properties in the lpPropTagArray parameter, set the property type in the recipient's ADRENTRY structure to PT_ERROR and the property value either to MAPI_E_NOT_FOUND or to another value giving a more specific reason for the unavailability. For information about PT_ERROR, see List of Property Types.

Note Never reallocate the ADRLIST structure that is passed into PrepareRecips or change its number of entries.

See Also

ADRLIST, IMAPIProp::GetProps, PR_ENTRYID, SPropValue


IABLogon::Unadvise

The IABLogon::Unadvise method cancels the sending of notifications previously set up with a call to the IABLogon::Advise method.

Quick Info

See IABLogon : IUnknown.

HRESULT Unadvise(
  ULONG ulConnection
);

Parameters

ulConnection
[in] Connection number associated with an active notification registration. The value of ulConnection must have been returned by a previous call to IABLogon::Advise.

Return Value

S_OK
The notification registration was successfully canceled.

Remarks

MAPI calls the IABLogon::Unadvise method to cancel a notification registration for a container, messaging user, or distribution list object.

Notes to Implementers

Your implementation of Unadvise will depend on whether you support notification with MAPI's help or manually. If MAPI provides your support, call IMAPISupport::Unsubscribe to cancel the registration. If you support notifications manually, call the IUnknown::Release method of the advise sink object passed in the lpAdviseSink parameter in Advise. Calling Release decrements the advise sink's reference count, allowing it to be freed when the count reaches zero. The call to Release can occur during the Unadvise method or, if another thread is in the process of calling the advise sink's IMAPIAdviseSink::OnNotify method, it can be delayed until OnNotify has returned.

For more information on the notification process, see Event Notification in MAPI. For information about using the IMAPISupport methods to support notification, see Supporting Event Notification.

See Also

IABLogon::Advise, IMAPIAdviseSink::OnNotify


IABProvider : IUnknown

The IABProvider interface provides a method to log on to an address book provider object and a method to invalidate an address book provider object.

Quick Info

Header file: | MAPISPI.H
Exposed by: | Address book provider objects
Implemented by: | Address book providers
Called by: | MAPI
Interface identifier: | IID_IABProvider
Pointer type: | LPABPROVIDER

Vtable Order

Shutdown | Cancels a connection to an active session.
Logon | Establishes a connection to an active session.


IABProvider::Logon

The IABProvider::Logon method establishes a connection to an active session.

Quick Info

See IABProvider : IUnknown.

HRESULT Logon(
  LPMAPISUP lpMAPISup,
  ULONG ulUIParam,
  LPTSTR lpszProfileName,
  ULONG ulFlags,
  ULONG FAR * lpulcbSecurity,
  LPBYTE FAR * lppbSecurity,
  LPMAPIERROR FAR * lppMAPIError,
  LPABLOGON FAR * lppABLogon
);

Parameters

lpMAPISup
[in] Pointer to the address book provider's support object.
ulUIParam
[in] Handle of the parent window for the logon dialog box that Logon displays if permitted. The ulUIParam parameter contains the value of the parameter of the same name passed to MAPI in the preceding call to the MAPILogonEx function.
lpszProfileName
[in] Pointer to the name of the session profile.
ulFlags
[in] Bitmask of flags that controls how the logon is performed. The following flags can be set:
AB_NO_DIALOG
The provider should not display a dialog box during logon. If this flag is not set, the provider can display a dialog box to prompt the user for missing configuration information.
MAPI_DEFERRED_ERRORS
Allows Logon to return successfully, possibly before the logon process is complete.
MAPI_UNICODE
All strings should be in Unicode format. If the MAPI_UNICODE flag is not set, the strings should be in ANSI format.
lpulcbSecurity
[in, out] Pointer to the size, in bytes, of the security credentials structure pointed to by the lppbSecurity parameter. On input, the value must be nonzero; on output, the value must be zero. In both cases the pointers must be valid.
lppbSecurity
[in, out] Pointer to a pointer to security credentials. On input, the value must be nonzero; on output, the value must be zero. In both cases the pointer must be valid.
lppMAPIError
[out] Pointer to a pointer to a MAPIERROR structure. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.
lppABLogon
[out] Pointer to a pointer to the provider's logon object.

Return Values

S_OK
A connection to an active session was successfully established.
MAPI_E_FAILONEPROVIDER
The provider cannot log on, but MAPI can continue to log on the other providers in the message service to which the provider belongs.
MAPI_E_UNCONFIGURED
The provider does not have enough information to complete the logon. MAPI calls the provider's message service entry function.
MAPI_E_UNKNOWN_CPID
The server is not configured to support the client's code page.
MAPI_E_UNKNOWN_LCID
The server is not configured to support the client's locale information.
MAPI_E_USER_CANCEL
The user canceled the operation, typically by clicking the Cancel button in the logon dialog box.

Remarks

Connections are established with each of the address book providers in the session profile when a client calls the IMAPISession::OpenAddressBook method. OpenAddressBook then calls each provider's IABProvider::Logon method.

The profile name pointed to by the lpszProfileName parameter is displayed in the character set of the user's client as indicated by the presence or absence of the MAPI_UNICODE flag in the ulFlags parameter.

Notes to Implementers

In your implementation of IABProvider::Logon, call IMAPISupport::SetProviderUID to register a unique identifier, or MAPIUID. Each of your objects will have an entry identifier that includes this MAPIUID. MAPI uses the MAPIUID to match an object with its provider. For example, when a client calls IMAPISession::OpenEntry to open a messaging user, OpenEntry examines the MAPIUID portion of the entry identifier passed in and matches it with a MAPIUID registered by an address book provider.

If a client logs on to your provider more than once, you may choose to register a different MAPIUID for each logon. Registering unique MAPIUIDs enables MAPI to correctly route requests to the appropriate provider instance. However, you may choose to have every logon object share one MAPIUID. In this case, you must be able to handle the routing yourself rather than relying on MAPI. For more information on creating one or more MAPIUIDs, see Registering Service Provider Unique Identifiers.

The support object that MAPI passes to your IABProvider::Logon method in the lpMAPISup parameter provides access to many of the methods included in the IMAPISupport interface. MAPI creates a support object specially tailored to your type of provider. For example, if you need to log on to an underlying messaging system or directory service when you establish your connection, you can call IMAPISupport::OpenProfileSection to retrieve security credentials for this particular logon session.

If IABProvider::Logon is successful, be sure to call the support object's IUnknown::AddRef method to increment its reference count. This allows your provider to hold onto the support object pointer for the remainder of the session. If you do not call this AddRef method, MAPI will unload your provider.

You can include the profile name passed in the lpszProfileName parameter in error dialog boxes, logon screens, or other user interfaces. To use the profile name, copy it to storage that you have allocated.

Create a logon object and return a pointer to it in the lppABLogon parameter. MAPI uses this logon object to make calls to the methods in your IABLogon implementation.

If you require a password during logon, display a logon dialog box only if the AB_NO_DIALOG flag is not set. If the user cancels the logon process, typically by clicking the Cancel button in the dialog box, return MAPI_E_USER_CANCEL from Logon.

Typically, when an address book provider cannot log on, MAPI disables the message service to which the failing provider belongs. That is, MAPI will not try to establish connections for any of the other providers belonging to the service for the rest of the session's lifetime. However, if your provider fails to establish a connection and you wish not to disable the entire service, return either MAPI_E_FAILONEPROVIDER or MAPI_E_UNCONFIGURED. MAPI will not disable the message service to which the provider belongs.

Return MAPI_E_FAILONEPROVIDER if an error occurs that is not serious enough to prevent the other providers in the message service from establishing connections. Return MAPI_E_UNCONFIGURED if necessary configuration information is missing from the profile and you cannot display a dialog box to prompt the user. MAPI will respond by calling your provider's message service entry point function with MSG_SERVICE_CONFIGURE set as the ulContext parameter to give the service a chance to configure itself, either programmatically or using a property sheet. When the message service entry point function has finished, MAPI retries the logon.

See Also

IABLogon::Logoff, IABLogon::OpenEntry, IMAPISupport::OpenProfileSection, IMAPISupport::SetProviderUID, MSGSERVICEENTRY


IABProvider::Shutdown

The IABProvider::Shutdown method cancels a connection to an active session.

Quick Info

See IABProvider : IUnknown.

HRESULT Shutdown (
  ULONG FAR * lpulFlags
);

Parameters

lpulFlags
Reserved; must be a pointer to zero.

Return Value

S_OK
The connection was successfully canceled.

Notes to Implementers

In your implementation of IABProvider::Shutdown, perform whatever tasks you deem necessary. MAPI calls your IABProvider::Shutdown method only after you have released all of your logon objects.


IAddrBook : IMAPIProp

The IAddrBook interface supports access to the MAPI address book and includes operations such as displaying common dialog boxes, opening containers, messaging users, and distribution lists, and performing name resolution.

Quick Info

Header file: | MAPIX.H
Exposed by: | Address book objects
Implemented by: | MAPI
Called by: | Client applications, service providers
Interface identifier: | IID_IAddrBook
Pointer type: | LPADRBOOK
Transaction model: | Not writable

Vtable Order

Note The implementation of IMAPIProp::GetLastError for IAddrBook supports Unicode on Windows NT platforms only. The implementations of GetLastError for Windows 95 platforms and 16-bit platforms do not support Unicode.

OpenEntry | Opens an address book entry and returns a pointer to an interface that can be used to access the entry.
CompareEntryIDs | Compares two entry identifiers belonging to a particular address book provider to determine if they refer to the same address book object.
Advise | Registers a client or service provider to receive notifications about changes to one or more entries in the address book.
Unadvise | Cancels a notification registration previously established for an address book entry.
CreateOneOff | Creates an entry identifier for a one-off address.
NewEntry | Adds a new recipient directly to an address book container or to the recipient list of an outgoing message.
ResolveName | Performs name resolution, assigning entry identifiers to recipients in a recipient list.
Address | Displays the common address dialog box.
Details | Displays a modal dialog box showing details about a particular address book entry.
RecipOptions | Displays a dialog box showing the recipient option properties.
QueryDefaultRecipOpt | Returns the recipient options that have been set for a particular address type by the transport provider.
GetPAB | Returns the entry identifier of the container designated as the personal address book (PAB).
SetPAB | Designates a particular container to be the personal address book (PAB).
GetDefaultDir | Returns the entry identifier for the address book container that is initially made available.
SetDefaultDir | Establishes a container as the default address book container — the container that is initially made available.
GetSearchPath | Returns an ordered list of entry identifiers of containers to be included in the name resolution process initiated by the IAddrBook::ResolveName method.
SetSearchPath | Sets a new search path in the profile that is used for the name resolution process.
PrepareRecips | Prepares a recipient list for later use by the messaging system.


IAddrBook::Address

The IAddrBook::Address method displays the common address dialog box.

Quick Info

See IAddrBook : IMAPIProp.

HRESULT Address(
  ULONG FAR * lpulUIParam,
  LPADRPARM lpAdrParms,
  LPADRLIST FAR * lppAdrList
);

Parameters

lpulUIParam
[in, out] Handle of the parent window of the dialog box. On input, a window handle must always be passed. On output, if the ulFlags member of the lpAdrParms parameter is set to DIALOG_SDI, then the window handle of the modeless dialog box is returned.
lpAdrParms
[in, out] Pointer to an ADRPARM structure that controls the presentation and behavior of the address dialog box.
lppAdrList
[in, out] Pointer to a pointer to an ADRLIST structure containing recipient information. On input, this parameter can be NULL or point to a valid pointer. On output, this parameter points to a pointer to valid recipient information.

Return Values

S_OK
The common address dialog box was successfully displayed.

Remarks

The ADRLIST structure passed back by MAPI to the caller through the lppAdrList parameter contains an array of ADRENTRY structures, one structure for each recipient. When passed to an outgoing message's IMessage::ModifyRecipients method in the lpMods parameter, the ADRLIST structure can be used to update its recipient list.

Each ADRENTRY structure in the ADRLIST structure contains zero or more SPropValue structures, one structure for every property set for the recipient. There can be zero SPropValue structures when the dialog box presented by IAddrBook::Address is used to remove a recipient. When there are one or more SPropValue structures, the corresponding ADRENTRY structure is used to add or update a recipient. The recipient can either be resolved, indicating that one of the SPropValue structures describes the recipient's PR_ENTRYID property, or unresolved, indicating that the PR_ENTRYID property is missing.

In addition to PR_ENTRYID, resolved recipients include the following properties:

PR_RECIPIENT_TYPE

PR_DISPLAY_NAME

PR_ADDRTYPE

PR_DISPLAY_TYPE

The ADRLIST structure that the caller passes in might be a different size from the structure that MAPI returns. If MAPI must return a larger ADRLIST structure, it frees the original structure and allocates a new one. When allocating memory for the ADRLIST structure, allocate the memory for each SPropValue structure separately. For more information about how to allocate and free ADRLIST structures, see Managing Memory for ADRLIST and SRowSet Structures

Address returns immediately if the DIALOG_SDI flag is set in the ulFlags member of the ADRPARM structure in the lpAdrParms parameter.

Address supports Unicode character strings in the ADRPARM and ADRLIST parameters for Windows NT platforms only. The Unicode strings are converted to the multibyte character string (MBCS) format before they are displayed in the common dialog box.

See Also

ADRENTRY, ADRLIST, ADRPARM, FreePadrlist, FreeProws, IMAPITable::QueryRows, IMessage::ModifyRecipients, MAPIAllocateBuffer, MAPIAllocateMore, MAPIFreeBuffer, SPropValue, SRowSet


IAddrBook::Advise

The IAddrBook::Advise method registers a client or service provider to receive notifications about changes to one or more entries in the address book.

Quick Info

See IAddrBook : IMAPIProp.

HRESULT Advise(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  ULONG ulEventMask,
  LPMAPIADVISESINK lpAdviseSink,
  ULONG FAR * lpulConnection
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the address book container, messaging user, or distribution list that will generate a notification when a change occurs of the type or types described in the ulEventMask parameter.
ulEventMask
[in] One or more notification events that the caller is registering to receive. Each event is associated with a particular notification structure containing information about the change that occurred. The following table lists the valid values for ulEventMask and their corresponding structures.
Notification event Corresponding structure
fnevCriticalError
 ERROR_NOTIFICATION
fnevObjectCreated
 OBJECT_NOTIFICATION
fnevObjectDeleted
 OBJECT_NOTIFICATION
fnevObjectModified
 OBJECT_NOTIFICATION
fnevObjectCopied
 OBJECT_NOTIFICATION
fnevObjectMoved
 OBJECT_NOTIFICATION
fnevTableModified
 TABLE_NOTIFICATION

lpAdviseSink
[in] Pointer to the advise sink object to be called when the event for which notification has been requested occurs.
lpulConnection
[out] Pointer to a nonzero connection number that represents the notification registration.

Return Values

S_OK
The notification registration was successful.
MAPI_E_INVALID_ENTRYID
The address book provider responsible for the entry identifier passed in lpEntryID could not register a notification for the corresponding entry.
MAPI_E_NO_SUPPORT
Notification is not supported by the address book provider responsible for the object identified by the entry identifier passed in the lpEntryID parameter.
MAPI_E_UNKNOWN_ENTRYID
The entry identifier passed in lpEntryID cannot be handled by any of the address book providers in the profile.

Remarks

Clients and service providers call the IAddrBook::Advise method to register for a particular type or types of notification on an address book entry. The types of notification are indicated by the event mask passed in with the lpEventMask parameter.

MAPI forwards this Advise call to the address book provider responsible for the entry as indicated by the entry identifier in the lpEntryID parameter. The address book provider either handles the registration itself or calls the support method, IMAPISupport::Subscribe, to prompt MAPI to register the caller. A nonzero connection number is returned to represent the successful registration.

Whenever a change occurs to the entry of the type indicated by the notification registration, the address book provider calls the IMAPIAdviseSink::OnNotify method for the advise sink object specified in the lpAdviseSink parameter. The OnNotify method includes a NOTIFICATION structure as an input parameter that contains data to describe the event.

Depending on the address book provider, the call to OnNotify can occur immediately following the change to the registered object or at some later time. On systems that support multiple threads of execution, the call to OnNotify can occur on any thread. Clients can request that these notifications occur on a particular thread by calling the HrThisThreadAdviseSink function to create the advise sink object that is passed to Advise.

Because an address book provider can release the advise sink object passed in by clients at any time after the successful completion of the Advise call and before an Unadvise call to cancel the notification, clients should release their advise sink objects when Advise returns.

For more information on the notification process, see Event Notification in MAPI.

See Also

HrThisThreadAdviseSink, IAddrBook::Unadvise, IMAPIAdviseSink::OnNotify, NOTIFICATION


IAddrBook::CompareEntryIDs

The IAddrBook::CompareEntryIDs method compares two entry identifiers belonging to a particular address book provider to determine if they refer to the same address book object.

Quick Info

See IAddrBook : IMAPIProp.

HRESULT CompareEntryIDs(
  ULONG cbEntryID1,
  LPENTRYID lpEntryID1,
  ULONG cbEntryID2,
  LPENTRYID lpEntryID2,
  ULONG ulFlags,
  ULONG FAR * lpulResult
);

Parameters

cbEntryID1
[in] Count of bytes in the entry identifier pointed to by the lpEntryID1 parameter.
lpEntryID1
[in] Pointer to the first entry identifier to be compared.
cbEntryID2
[in] Count of bytes in the entry identifier pointed to by the lpEntryID2 parameter.
lpEntryID2
[in] Pointer to the second entry identifier to be compared.
ulFlags
Reserved; must be zero.
lpulResult
[out] Pointer to the result of the comparison. The contents of lpulResult is set to TRUE if the two entry identifiers refer to the same object, and FALSE otherwise.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_UNKNOWN_ENTRYID
One or both of the entry identifiers passed in with the lpEntryID1 or lpEntryID2 parameters are not recognized by any address book provider.

Remarks

Client applications and service providers call the IAddrBook::CompareEntryIDs method to compare two entry identifiers belonging to a single address book provider to determine if they refer to the same object. CompareEntryIDs is useful because an object can have more than one valid entry identifier; such a situation can occur, for example, after a new version of an address book provider is installed.

MAPI passes this call on to the address book provider responsible for the entry identifiers, determining the appropriate provider by matching the MAPIUID structure in the entry identifiers with the MAPIUID structure registered by the provider.

If the two entry identifiers refer to the same object, then CompareEntryIDs sets the contents of the lpulResult parameter to TRUE; if they refer to different objects, CompareEntryIDs sets it to FALSE. In either case, CompareEntryIDs returns S_OK. If CompareEntryIDs returns an error, which can occur if no address book provider has registered a MAPIUID structure that matches the one in the entry identifiers, clients and providers should not take any action based on the result of the comparison. They should instead take the most conservative approach to the action being performed.


IAddrBook::CreateOneOff

The IAddrBook::CreateOneOff method creates an entry identifier for a one-off address.

Quick Info

See IAddrBook : IMAPIProp.

HRESULT CreateOneOff(
  LPTSTR lpszName,
  LPTSTR lpszAdrType,
  LPTSTR lpszAddress,
  ULONG ulFlags,
  ULONG FAR * lpcbEntryID,
  LPENTRYID FAR * lppEntryID
);

Parameters

lpszName
[in] Pointer to the display name of the recipient — the PR_DISPLAY_NAME property. The lpszName parameter can be NULL.
lpszAdrType
[in] Pointer to the address type of the recipient, such as FAX or SMTP. The lpszAdrType parameter cannot be NULL.
lpszAddress
[in] Pointer to the address of the recipient. The lpszAddress parameter cannot be NULL.
ulFlags
[in] Bitmask of flags that that affects the one-off recipient. The following flags can be set:
MAPI_SEND_NO_RICH_INFO
The recipient cannot handle formatted message content. If MAPI_SEND_NO_RICH_INFO is set, MAPI sets the recipient's PR_SEND_RICH_INFO property to FALSE. If MAPI_SEND_NO_RICH_INFO is not set, MAPI sets this property to TRUE unless the recipient's messaging address pointed to by lpszAddress is interpreted to be an Internet address. In this case, MAPI sets PR_SEND_RICH_INFO to FALSE.
MAPI_UNICODE
The display name, address type, and address are in Unicode format. If the MAPI_UNICODE flag is not set, these strings are in ANSI format.
lpcbEntryID
[out] Pointer to the count of bytes in the entry identifier pointed to by the lppEntryID parameter.
lppEntryID
[out] Pointer to a pointer to the entry identifier for the one-off recipient.

Return Values

S_OK
The one-off entry identifier was created successfully.

Remarks

Clients call the IAddrBook::CreateOneOff method to create an entry identifier for a one-off recipient — a recipient that does not belong to any of the containers from any of the currently loaded address book providers. One-off recipients can have any type of address that is supported by one of the active address book providers for the session.

One-off recipients are typically created with a template for their particular address type. The address book provider that supports the address type supplies the template. A user of a client application enters the relevant information into the template.

MAPI supports Unicode character strings for the display name, address type, and address parameters to CreateOneOff on Windows NT platforms only.

The MAPI_SEND_NO_RICH_INFO flag controls whether or not formatted text in Rich Text Format (RTF) is sent along with each message. The Transport Neutral Encapsulation Format (TNEF) — a format used for transmitting formatted text — is sent by most transport providers, regardless of how the recipient sets its PR_SEND_RICH_INFO property. This is not an issue for messaging clients that work with interpersonal messages, but because TNEF is typically used to send custom properties for custom message classes, not supporting it can be a problem for form-based clients or clients that require custom MAPI properties. For more information, see Sending Messages with TNEF.

See Also

IMAPISupport::CreateOneOff


IAddrBook::Details

The IAddrBook::Details method displays a modal dialog box showing details about a particular address book entry.

Quick Info

See IAddrBook : IMAPIProp.

HRESULT Details(
  ULONG FAR * lpulUIParam,
  LPFNDISMISS lpfnDismiss,
  LPVOID lpvDismissContext,
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  LPFNBUTTON lpfButtonCallback,
  LPVOID lpvButtonContext,
  LPTSTR lpszButtonText,
  ULONG ulFlags
);

Parameters

lpulUIParam
[out] Handle of the parent window for the dialog box.
lpfnDismiss
[in] Pointer to a function based on the DISMISSMODELESS function prototype. This function is called when the modeless variety of the details dialog box is dismissed. This parameter is ignored at present because MAPI does not support a modeless details dialog box.
lpvDismissContext
[in] Data that is passed to the function specified by the lpfnDismiss parameter. This parameter is currently ignored.
cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier for the entry for which details are displayed.
lpfButtonCallback
[in] Pointer to a function based on the LPFNBUTTON function prototype. An LPFNBUTTON function adds a button to the details dialog box.
lpvButtonContext
[in] Pointer to data used as a parameter for the function specified by the lpfButtonCallback parameter.
lpszButtonText
[in] Pointer to a string containing text to be applied to the added button if that button is extensible. The lpszButtonText parameter should be NULL if an extensible button is not needed.
ulFlags
[in] Bitmask of flags that controls the type of the text for the lpszButtonText parameter. The following flag can be set:
MAPI_UNICODE
The passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.

Return Values

S_OK
The details dialog box was successfully displayed for the address book entry.

Remarks

Client applications call the IAddrBook::Details method to display a modal dialog box giving details on a particular entry in the address book. The lpfButtonCallback, lpvButtonContext, and lpButtonText parameters can be used to add a button the client has defined to the dialog box. When the button is clicked, MAPI calls the callback function pointed to by lpfButtonCallback, passing both the entry identifier of the button and the data in lpvButtonContext. If an extensible button is not needed, lpszButtonText should be NULL.

Details supports Unicode character strings for Windows NT platforms only. The Unicode strings are converted to the multibyte character string (MBCS) format before they are displayed in the details dialog box.

See Also

IAddrBook::Address, LPFNBUTTON


IAddrBook::GetDefaultDir

The IAddrBook::GetDefaultDir method returns the entry identifier for the address book container that is initially made available.

Quick Info

See IAddrBook : IMAPIProp.

HRESULT GetDefaultDir(
  ULONG FAR * lpcbEntryID,
  LPENTRYID FAR * lppEntryID
);

Parameters

lpcbEntryID
[out] Pointer to the count of bytes in the entry identifier pointed to by the lppEntryID parameter.
lppEntryID
[out] Pointer to a pointer to the entry identifier of the default container.

Return Values

S_OK
The entry identifier of the default container was successfully returned.

Remarks

Client applications and service providers call the IAddrBook::GetDefaultDir method to retrieve the entry identifier of the default address book container. The default container is what the user sees displayed in the address book when the address book is first opened. If a default container has not been set by a call to the IAddrBook::SetDefaultDir method, MAPI assigns as the default container the first container with names that is not the personal address book (PAB). If such a container cannot be found, the PAB becomes the default container.

To set the default directory, a client or provider calls the IAddrBook::SetDefaultDir method. Clients and providers need not call the IMAPIProp::SaveChanges method; because changes to the address book are not transacted, changes are immediately made permanent.

See Also

IAddrBook::SetDefaultDir, MAPIAllocateBuffer, MAPIFreeBuffer, PR_CONTAINER_FLAGS


IAddrBook::GetPAB

The IAddrBook::GetPAB method returns the entry identifier of the container designated as the personal address book (PAB).

Quick Info

See IAddrBook : IMAPIProp.

HRESULT GetPAB(
  ULONG FAR * lpcbEntryID,
  LPENTRYID FAR * lppEntryID
);

Parameters

lpcbEntryID
[out] Pointer to the count of bytes in the entry identifier pointed to by the lppEntryID parameter.
lppEntryID
[out] Pointer to a pointer to the entry identifier of the PAB. The lppEntryID parameter contains zero if no container has been designated as the PAB.

Return Values

S_OK
The entry identifier of the PAB was successfully returned.

Remarks

Clients call the IAddrBook::GetPAB method to retrieve the entry identifier of the container designated as the PAB. If a PAB has not been established in the profile, MAPI selects as the PAB the first container in the address book hierarchy that allows modifications.

See Also

MAPIAllocateBuffer, MAPIFreeBuffer, PR_CONTAINER_FLAGS


IAddrBook::GetSearchPath

The IAddrBook::GetSearchPath method returns an ordered list of entry identifiers of containers to be included in the name resolution process initiated by the IAddrBook::ResolveName method.

Quick Info

See IAddrBook : IMAPIProp.

HRESULT GetSearchPath(
  ULONG ulFlags,
  LPSRowSet FAR * lppSearchPath
);

Parameters

ulFlags
[in] Bitmask of flags that controls the type of the strings returned in the search path. The following flag can be set:
MAPI_UNICODE
The returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppSearchPath
[out] Pointer to a pointer to an ordered list of container entry identifiers. GetSearchPath stores the ordered list in an SRowSet structure. If there are no containers in the address book hierarchy, zero is returned in the SRowSet structure.

Return Values

S_OK
The search path was successfully retrieved.

Remarks

Clients and service providers call the IAddrBook::GetSearchPath method to get the search path that is used to resolve names with IAddrBook::ResolveName. Typically, clients call the IAddrBook::SetSearchPath method to establish a container search path in the profile before they call GetSearchPath to retrieve it. However, calling SetSearchPath is optional.

If SetSearchPath has never been called, GetSearchPath builds a path by working through the address book's hierarchy tables. The default search path established by GetSearchPath is made up of the following containers in the following order:

  1. The first container with read/write access, usually the personal address book (PAB).
  2. Every container that has its PR_DISPLAY_TYPE property set to DT_GLOBAL. Such a setting indicates that the container holds recipients.
  3. The container designated as the default, if there are no containers that have the DT_GLOBAL flag set in their PR_DISPLAY_TYPE property and the default container is not the same as the first container with read/write access.

If SetSearchPath has been called, GetSearchPath builds a path using the address book containers that have been stored in the profile. GetSearchPath validates this path before returning it to the caller.

After the first call to SetSearchPath, subsequent calls to SetSearchPath must be used to modify the search path returned by GetSearchPath. In other words, the calling client or provider does not receive the default search path after the first call to SetSearchPath.

See Also

IAddrBook::SetSearchPath, SRowSet


IAddrBook::NewEntry

The IAddrBook::NewEntry method adds a new recipient directly to an address book container or to the recipient list of an outgoing message.

Quick Info

See IAddrBook : IMAPIProp.

HRESULT NewEntry(
  ULONG ulUIParam,
  ULONG ulFlags,
  ULONG cbEIDContainer,
  LPENTRYID lpEIDContainer,
  ULONG cbEIDNewEntryTpl,
  LPENTRYID lpEIDNewEntryTpl,
  ULONG FAR * lpcbEIDNewEntry,
  LPENTRYID FAR * lppEIDNewEntry
);

Parameters

ulUIParam
[in] Handle of the parent window for the dialog box.
ulFlags
Reserved; must be zero.
cbEIDContainer
[in] Count of bytes in the entry identifier pointed to by the lpEIDContainer parameter.
lpEIDContainer
[in] Pointer to the entry identifier of the container where the new recipient is to be added. If the cbEIDContainer parameter is zero, NewEntry returns a recipient entry identifier and a list of templates as if the IAddrBook::CreateOneOff method was called.
cbEIDNewEntryTpl
[in] Count of bytes in the entry identifier pointed to by the lpEIDNewEntryTpl parameter.
lpEIDNewEntryTpl
[in] Pointer to a one-off template to be used to create the new recipient. If cbEIDNewEntryTpl is zero and lpEIDNewEntryTpl is NULL, NewEntry displays a dialog box enabling the user to select from a list of templates for adding new entries.
lpcbEIDNewEntry
[out] Pointer to the count of bytes in the entry identifier pointed to by the lppEIDNewEntry parameter.
lppEIDNewEntry
[out] Pointer to a pointer to the new recipient's entry identifier.

Return Values

S_OK
The new address book entry was successfully created.

Remarks

The IAddrBook::NewEntry method creates a new address book entry, to be added directly into a container or to be used to address an outgoing message.

Notes to Callers

If you want the new entry to be added to a specific container, set lpEIDContainer to the container's entry identifier and cbEIDContainer to the count of bytes in the entry identifier.

If you want the new entry to be added to the recipient list of an outgoing message, set lpEIDContainer to NULL and cbEIDContainer to zero.

If you want to allow the user of a client application to select the type of entry to be created, pass zero in cbEIDNewEntryTpl and NULL in lpEIDNewEntryTpl. NewEntry displays the MAPI one-off table, a listing of templates supported by MAPI and by each of the address book providers in the session. Each template can create a recipient entry for one or more address types.

If you want to retain the entry identifier of the new entry, pass valid pointers in the lpcbEIDNewEntry and lppEIDNewEntry parameters. You are responsible for freeing this entry identifier when you have finished with it by calling the MAPIFreeBuffer function.

To use a particular template for adding a new entry to a modifiable container
  1. Call IMAPISession::OpenEntry to open the destination container, setting the lpEntryID parameter to the entry identifier of the container.
  2. Call the destination container's IMAPIProp::OpenProperty method and set ulPropTag to PR_CREATE_TEMPLATES and lpiid to IID_IMAPITable. The container will return a one-off table listing all of the templates that it supports for creating new entries.
  3. Retrieve the row that represents the template for the particular type of entry you want to create. The PR_ADDRTYPE column indicates the address type that is supported by the template.
  4. Call IAddrBook::NewEntry and set lpEIDNewEntryTpl to the entry identifier of the selected template. This will be the PR_ENTRYID column from the template's row in the one-off table. Pass zero in cbEIDContainer and NULL in lpEIDContainer. Pass a valid pointer in the lppEIDNewEntry parameter if you want to retain the new entry's entry identifier.

See Also

IAddrBook::OpenEntry, IMAPIProp::OpenProperty, PR_CREATE_TEMPLATES


IAddrBook::OpenEntry

The IAddrBook::OpenEntry method opens an address book entry and returns a pointer to an interface that can be used to access the entry.

Quick Info

See IAddrBook : IMAPIProp.

HRESULT OpenEntry(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  LPCIID lpInterface,
  ULONG ulFlags,
  ULONG FAR * lpulObjType,
  LPUNKNOWN FAR * lppUnk
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier representing the address book entry to open.
lpInterface
[in] Pointer to the interface identifier (IID) of the interface to be used to access the open entry. Passing NULL results in the object's standard interface being returned. For messaging users, the standard interface is IMailUser. For distribution lists, it is IDistList and for containers, it is IABContainer. Callers can set lpInterface to the appropriate standard interface or an interface in the inheritance hierarchy.
ulFlags
[in] Bitmask of flags that controls how the entry is opened. The following flags can be set:
MAPI_BEST_ACCESS
Requests that the entry be opened with the maximum allowable network and client permissions. For example, if the client has read/write access, the address book provider should attempt to open the entry with read/write access.

The client can retrieve the access level that was granted by calling the open entry's IMAPIProp::GetProps method and retrieving the PR_ACCESS_LEVEL property.

MAPI_DEFERRED_ERRORS
Allows the call to succeed potentially before the entry is fully open and accessible, implying that subsequent calls to the entry might return an error.
MAPI_MODIFY
Requests that the entry be opened with read/write access. Because by default, entries are opened with read-only access, clients should not assume that read/write access has been granted regardless of whether MAPI_MODIFY is set.
lpulObjType
[out] Pointer to the type of the opened entry.
lppUnk
[out] Pointer to a pointer to the opened entry.

Return Values

S_OK
The entry was successfully opened.
MAPI_E_NO_ACCESS
An attempt was made to open an entry for which the user has insufficient permissions.
MAPI_E_NOT_FOUND
The entry represented by lpEntryID does not exist.
MAPI_E_UNKNOWN_ENTRYID
The entry identifier specified in lpEntryID is not recognized. This value is typically returned if the address book provider responsible for the corresponding entry is not open.

Remarks

Clients and service providers call the IAddrBook::OpenEntry method to open an address book entry. MAPI forwards the call to the appropriate address book provider, based on the MAPIUID structure included in the entry identifier passed in the lpEntryID parameter. The address book provider opens the entry as read-only unless the MAPI_MODIFY or MAPI_BEST_ACCESS flag in the ulFlags parameter is set. However, these flags are suggestions. If the address book provider does not allow modification for the entry requested, then it returns MAPI_E_NO_ACCESS.

The lpInterface parameter indicates which interface should be used to access the opened entry. Passing NULL in lpInterface indicates the standard MAPI interface for that type of entry should be used. Because the address book provider might return a different interface than the one suggested by the lpInterface parameter, the caller should check the value returned in the lpulObjType parameter to determine that the object type returned is what was expected. If the object type is not of the type expected, the caller can cast the lppUnk parameter to a type that is more appropriate.


IAddrBook::PrepareRecips

The IAddrBook::PrepareRecips method prepares a recipient list for later use by the messaging system.

Quick Info

See IAddrBook : IMAPIProp.

HRESULT PrepareRecips(
  ULONG ulFlags,
  LPSPropTagArray lpSPropTagArray,
  LPADRLIST lpRecipList
);

Parameters

ulFlags
Reserved; must be zero.
lpSPropTagArray
[in] Pointer to an SPropTagArray structure containing an array of property tags indicating properties that require updating, if any. The lpSPropTagArray parameter can be NULL.
lpRecipList
[in] Pointer to an ADRLIST structure holding the list of recipients.

Return Values

S_OK
The recipient list was successfully prepared.

Remarks

Clients and service providers call the IAddrBook::PrepareRecips method to:

  • Ensure that all recipients in the lpRecipList parameter have long-term entry identifiers.
  • Ensure that each recipient in the lpRecipList parameter has the properties listed in the lpSPropTagArray parameter and that these properties appear at the beginning of the recipient list.

MAPI converts each recipient's short-term entry identifiers to long-term entry identifiers. If necessary, recipients' long-term entry identifiers are retrieved from the appropriate address book provider along with any additional properties requested.

Within an individual recipient entry, the requested properties are ordered first, followed by any additional properties that were already present for the entry. If one or more of the requested properties, the properties included in the lpSPropTagArray, are not handled by the appropriate address book provider, their property types will be set to PT_ERROR and their property values either to MAPI_E_NOT_FOUND or to another value giving a more specific reason why the properties are not available. Each SPropValue structure included in the lpSPropTagArray parameter must be separately allocated using the MAPIAllocateBuffer and MAPIAllocateMore functions such that it can be freed individually.

For information on PT_ERROR, see List of Property Types.

See Also

ADRLIST, IMAPIProp::GetProps, IMessage::ModifyRecipients, PR_ENTRYID, SPropValue, SRowSet


IAddrBook::QueryDefaultRecipOpt

The IAddrBook::QueryDefaultRecipOpt method returns the recipient options that have been set for a particular address type by the transport provider.

Quick Info

See IAddrBook : IMAPIProp.

HRESULT QueryDefaultRecipOpt(
  LPTSTR lpszAdrType,
  ULONG ulFlags,
  ULONG FAR * lpcValues,
  LPSPropValue FAR * lppOptions
);

Parameters

lpszAdrType
[in] Pointer to a valid address type. The lpszAdrType parameter must not be NULL.
ulFlags
[in] Bitmask of flags that controls the type of the string passed in with the lpszAdrType parameter. The following flag can be set:
MAPI_UNICODE
The address type string is in Unicode format. If the MAPI_UNICODE flag is not set, the address type is in ANSI format.
lpcValues
[out] Pointer to the number of property values in the lppOptions parameter.
lppOptions
[out] Pointer to an array of SPropValue structures describing the recipient option properties.

Return Values

S_OK
The recipient option properties were successfully returned.

Remarks

Recipient options are properties that are set by a transport provider when MAPI calls its IXPLogon::RegisterOptions method. Not all transport providers register recipient options. Recipient options are usually, but not always, specific to a particular address type.

Clients and service providers call the IAddrBook::QueryDefaultRecipOpt method to programmatically retrieve the recipient options for a particular address type. If a client must display a dialog box with these options, the client should call the IAddrBook::RecipOptions method.

Transport providers can also register message options that apply to all recipients. For more information on registering options, see Implementing Message and Recipient Options with Transport Providers.

See Also

IAddrBook::RecipOptions, IMAPISession::MessageOptions, IMAPISession::QueryDefaultMessageOpt


IAddrBook::RecipOptions

The IAddrBook::RecipOptions method displays a dialog box showing the recipient option properties.

Quick Info

See IAddrBook : IMAPIProp.

HRESULT RecipOptions(
  ULONG ulUIParam,
  ULONG ulFlags,
  LPADRENTRY lpRecip
);

Parameters

ulUIParam
[in] Handle of the parent window for the dialog box.
ulFlags
Reserved; must be zero.
lpRecip
[in] Pointer to the ADRENTRY structure that describes the recipient whose options are to be displayed.

Return Values

S_OK
The options for the specified recipient were successfully displayed.
MAPI_W_ERRORS_RETURNED
There are no recipient options for this recipient. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. For more information on using the HR_FAILED macro, see Using Macros for Error Handling.

Remarks

Clients and service providers call the IAddrBook::RecipOptions method to display a dialog box to allow a user to set properties that control the sending and receiving of messages for a particular recipient and address type.

To locate the appropriate properties to be displayed, MAPI first scans through the SPropValue structure array in the ADRENTRY structure to find the PR_ENTRYID and PR_ADDRTYPE properties. MAPI then determines the transport provider, if any, that has registered options for the particular address type. If there is an appropriate transport provider, MAPI calls the provider's function that is based on the OPTIONCALLBACK prototype to retrieve the properties.

To retrieve the set of default recipient options without presenting a dialog box to the user, clients or service providers should call the IAddrBook::QueryDefaultRecipOpt method.

If any recipient options are changed on a RecipOptions call, MAPI frees the old SPropValue structures for those options within the recipient's ADRENTRY structure and allocates new ones.

If there are no recipient options available for the address type indicated in the lpRecip parameter, the warning MAPI_W_ERRORS_RETURNED is returned, indicating there was an error returned for the RecipOptions call. Calling the IMAPIProp::GetLastError method returns a text string describing the warning.

Transport providers can also register message options that apply to all recipients. For more information on registering options, see Implementing Message and Recipient Options with Transport Providers.

See Also

ADRENTRY, IAddrBook::QueryDefaultRecipOpt, IMAPISession::MessageOptions, IMAPISession::QueryDefaultMessageOpt, SPropValue


IAddrBook::ResolveName

The IAddrBook::ResolveName method performs name resolution, assigning entry identifiers to recipients in a recipient list.

Quick Info

See IAddrBook : IMAPIProp.

HRESULT ResolveName(
  ULONG ulUIParam,
  ULONG ulFlags,
  LPTSTR lpszNewEntryTitle,
  LPADRLIST lpAdrList
);

Parameters

ulUIParam
[in] Handle of the parent window for a dialog box that is shown, if necessary, to prompt the user to resolve ambiguity.
ulFlags
[in] Bitmask of flags that controls whether a dialog box can be displayed. The following flag can be set:
MAPI_DIALOG
Allows the display of a dialog box to prompt the user for additional name resolution information. If this flag is not set, no dialog box is displayed.
lpszNewEntryTitle
[in] Pointer to text for the title of the control in the dialog box that prompts the user to enter a recipient. The title varies depending on the type of recipient. The lpszNewEntryTitle parameter can be NULL.
lpAdrList
[in-out] Pointer to an ADRLIST structure containing the list of recipient names to be resolved. This ADRLIST structure can be created by the IAddrBook::Address method.

Return Values

S_OK
The name resolution process succeeded.
MAPI_E_AMBIGUOUS_RECIP
At least one recipient in the lpAdrList parameter matched more than one entry in the address book. Usually, this value is returned when the MAPI_DIALOG flag is set, prohibiting the display of a dialog box.
MAPI_E_NOT_FOUND
At least one recipient in the lpAdrList parameter cannot be resolved. Usually, this value is returned when the MAPI_DIALOG flag is set, prohibiting the display of a dialog box.

Remarks

Clients and service providers call the IAddrBook::ResolveName method to initiate the name resolution process. An unresolved entry is an entry that does not yet have an entry identifier — or PR_ENTRYID property.

ResolveName goes through the following process for each unresolved entry in the address list passed in the lpAdrList parameter:

  1. If the address type of the recipient adheres to the format of an SMTP address (displayname@address.addresslist), IAddrBook::ResolveName assigns it a one-off entry identifier.
  2. For each container in the PR_AB_SEARCH_PATH property, IAddrBook::ResolveName calls the IABContainer::ResolveNames method. IABContainer::ResolveNames tries to match the display name of each unresolved recipient with a display name belonging to one of its entries.
  3. If a container does not support IABContainer::ResolveNames, IAddrBook::ResolveName restricts the container's contents table using a PR_ANR property restriction. This restriction causes the container to perform a "best guess" type of search to locate a matching recipient. All containers must support the PR_ANR property restriction.
  4. When a container returns a recipient that matches multiple names, IAddrBook::ResolveName displays a dialog box — if the MAPI_DIALOG flag is set — allowing the user to select the correct name.
  5. If all of the containers in the PR_AB_SEARCH_PATH property have been called and no match has been found, the recipient remains unresolved.

If one or more recipients are unresolved, IAddrBook::ResolveName returns MAPI_E_NOT_FOUND. If one or more recipients had ambiguous resolution that could not be resolved with a dialog box because the MAPI_DIALOG flag was not set, IAddrBook::ResolveName returns MAPI_E_AMBIGUOUS_RECIP. When some of the recipients are ambiguous and some cannot be resolved, IAddrBook::ResolveName can return either error value.

If a name cannot be resolved, the client can create a one-off address with a specially formatted address and entry identifier. For more information about the format of one-off entry identifiers, see One-Off Entry Identifiers. For more information about the format of one-off addresses, see One-Off Addresses.

MAPI supports Unicode character strings for the ADRLIST and the new entry title parameters to ResolveName on Windows NT platforms only.

See Also

ADRLIST, IABContainer::ResolveNames, IAddrBook::Address


IAddrBook::SetDefaultDir

The IAddrBook::SetDefaultDir method establishes a container as the default address book container — the container that is initially made available.

Quick Info

See IAddrBook : IMAPIProp.

HRESULT SetDefaultDir(
  ULONG cbEntryID,
  LPENTRYID lpEntryID
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the default address book container.

Return Values

S_OK
The default address book container was successfully set.

Remarks

Clients and service providers call the IAddrBook::SetDefaultDir method to establish a new default address book container. The default container is the container that the user sees displayed in the address book when the address book is first opened. SetDefaultDir saves the default container as an entry in the profile. The container remains as the default either until another call to SetDefaultDir is made — in the same session or in another session — or the container is removed.

See Also

IAddrBook::GetDefaultDir, IAddrBook::GetSearchPath, IMAPISession::Logoff, MAPILogonEx


IAddrBook::SetPAB

The IAddrBook::SetPAB method designates a particular container to be the personal address book (PAB).

Quick Info

See IAddrBook : IMAPIProp.

HRESULT SetPAB(
  ULONG cbEntryID,
  LPENTRYID lpEntryID
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the container to be designated as the PAB. The lpEntryID parameter cannot be NULL.

Return Values

S_OK
The specified container has been established as the PAB.

Remarks

Clients and service providers call the IAddrBook::SetPAB method to designate a particular container to be the PAB. The PAB is a container that is made up of entries copied from other containers as well as new entries.

Because information about the PAB is written in the profile, a particular container can be the PAB for multiple sessions. A call to SetPAB establishes a container as the PAB until that container is made unavailable or a new container becomes the PAB through a subsequent call to SetPAB.

Clients and providers need not call the IMAPIProp::SaveChanges method to make the PAB change permanent.

See Also

IAddrBook::GetPAB, IAddrBook::GetSearchPath, PR_CONTAINER_FLAGS


IAddrBook::SetSearchPath

The IAddrBook::SetSearchPath method sets a new search path in the profile that is used for the name resolution process.

Quick Info

See IAddrBook : IMAPIProp.

HRESULT SetSearchPath(
  ULONG ulFlags,
  LPSRowSet lpSearchPath
);

Parameters

ulFlags
Reserved; must be zero.
lpSearchPath
[in] Pointer to the SRowSet structure used to hold the search path. The first property for each aRow member in the SRowSet must be PR_ENTRYID.

Return Values

S_OK
The search path was successfully set.
MAPI_E_MISSING_REQUIRED_COLUMN
One of the containers described in the SRowSet structure did not include its PR_ENTRYID property.

Remarks

Clients and service providers call the IAddrBook::SetSearchPath method to save changes made to the container search order that is used to resolve names with IAddrBook::ResolveName. The search path is saved between instances of a session. This functionality means that, after a call to the IMAPISession::Logoff method, subsequent calls to the MAPILogonEx function during the same session return the same search path as previously set, as long as that search path still exists.

Clients and providers need not call the IMAPIProp::SaveChanges method to make the search path changes permanent.

See Also

IAddrBook::GetDefaultDir, IAddrBook::GetPAB, IAddrBook::GetSearchPath, PR_CONTAINER_FLAGS


IAddrBook::Unadvise

The IAddrBook::Unadvise method cancels a notification registration previously established for an address book entry.

Quick Info

See IAddrBook : IMAPIProp.

HRESULT Unadvise(
  ULONG ulConnection
);

Parameters

ulConnection
[in] Connection number that represents the registration to be canceled. The ulConnection parameter should contain a value returned by a prior call to IAddrBook::Advise.

Return Values

S_OK
The registration was successfully canceled.

Remarks

Clients call the IAddrBook::Unadvise method to stop receiving notifications about changes to a particular address book entry. When a notification registration is canceled, the address book provider releases its pointer to the caller's advise sink. However, the release can occur during the Unadvise call or at some later point, if another thread is in the process of calling IMAPIAdviseSink::OnNotify. When a notification is in progress, the release is delayed until the OnNotify method returns.

See Also

IAddrBook::Advise, IMAPIAdviseSink::OnNotify


IAttach : IMAPIProp

The IAttach interface is used to maintain and provide access to the properties of attachments in messages. The IAttach interface has no unique methods of its own.

For more information about using attachments, see Attachments and Attachment Tables.

Quick Info

Header file: | MAPIDEFS.H
Exposed by: | Attachment objects
Implemented by: | Message store providers
Called by: | Client applications
Interface identifier: | IID_IAttachment
Pointer type: | LPATTACH
Transaction model: | Transacted

Vtable Order

No unique methods

Required properties | Access
PR_OBJECT_TYPE | Read-only
PR_ATTACH_METHOD | Read/write
PR_RENDERING_POSITION | Read/write


IDistList : IMAPIContainer

The IDistList interface is used to provide access to distribution lists in modifiable address book containers. IDistList can create, copy, and delete distribution lists, in addition to performing name resolution.

Quick Info

Header file: | MAPIDEFS.H
Exposed by: | Distribution list objects
Implemented by: | Address book providers
Called by: | Client applications
Interface identifier: | IID_IDistList
Pointer type: | LPDISTLIST
Transaction model: | Transacted

Vtable Order

No unique methods

Required properties | Access
PR_ADDRTYPE | Read/write
PR_DISPLAY_NAME | Read/write
PR_ENTRYID | Read-only
PR_OBJECT_TYPE | Read-only
PR_RECORD_KEY | Read-only

Remarks

The IDistList interface inherits from IMAPIContainer and includes the same methods as address book containers. Therefore, because the methods of the IDistList interface are identical to those of the IABContainer interface, they are not redocumented here.

A distribution list — or object that implements IDistList — is a collection of messaging user objects, or individual recipients. A distribution list can be made up of all messaging user objects, or some messaging user and some distribution lists.

There are typically two types of distribution lists:

  • Distribution lists that are expanded by the underlying messaging system. This type of list has an address, PR_EMAIL_ADDRESS, and is treated the same as if it were an individual recipient.
  • Distribution lists that exist in a local container and are expanded by the client application.

Optional distribution list properties include:

PR_LAST_MODIFICATION_TIME

PR_DISPLAY_TYPE

PR_DETAILS_TABLE

Notice that PR_ADDRTYPE is required, but PR_EMAIL_ADDRESS is not. That is because a distribution list without an e-mail address can still receive messages, but its member list must be expanded. If the PR_ADDRTYPE property is set to MAPIPDL, MAPI performs the expansion. If PR_ADDRTYPE is a value other than MAPIPDL, the transport provider performs the expansion.

For further information on using the IDistList methods, see the reference entries for the parallel methods of IABContainer.


IMailUser : IMAPIProp

The IMailUser interface is implemented by messaging user objects. IMailUser inherits from the IMAPIProp interface and has no unique methods of its own. The IMailUser interface provides access to the many properties that are associated with messaging users.

Quick Info

Header file: | MAPIDEFS.H
Exposed by: | Messaging user objects
Implemented by: | Address book providers
Called by: | Client applications
Interface identifier: | IID_IMailUser
Pointer type: | LPMAILUSER
Transaction model: | Transacted

Vtable Order

No unique methods

Required properties | Access
PR_ADDRTYPE | Read/write
PR_DISPLAY_NAME | Read/write
PR_DISPLAY_TYPE | Read-only
PR_EMAIL_ADDRESS | Read/write
PR_ENTRYID | Read-only
PR_OBJECT_TYPE | Read-only
PR_RECORD_KEY | Read-only
PR_SEARCH_KEY | Read-only

Remarks

Five of the required properties are known as the base address properties for recipients:

PR_ADDRTYPE

PR_DISPLAY_NAME

PR_EMAIL_ADDRESS

PR_ENTRYID

PR_SEARCH_KEY

These properties are considered special because many other groups of similar properties are built upon this base group. The other groups are used to describe a recipient in various roles, such as a message's original or delegate sender. For more information about these properties and how to use them, see Address Types.

Messaging users can display a collection of their properties by supporting the PR_DETAILS_TABLE property. PR_DETAILS_TABLE is a display table that describes the layout of a details dialog box — a tabbed property page dedicated to showing recipient property information. Details dialog boxes are created by MAPI when a client calls the IAddrBook::Details method.

Messaging user objects can have other optional properties associated with them. MAPI defines over forty properties that provide additional addressing information about a messaging user. All of these properties are character strings. The more commonly used properties are:

PR_ACCOUNT

PR_ASSISTANT

PR_BUSINESS_TELEPHONE_NUMBER

PR_GIVEN_NAME

PR_GOVERNMENT_ID_NUMBER

PR_LOCALITY

PR_POSTAL_ADDRESS

For a complete list of these properties, see Personal Information Properties.


IMAPIAdviseSink : IUnknown

The IMAPIAdviseSink interface is used to implement an advise sink object for handling notification. A pointer to an advise sink object is passed in a call to a service provider's Advise method, the mechanism used to register for notification.

Quick Info

Header file: | MAPIDEFS.H
Exposed by: | Advise sink objects
Implemented by: | Client applications and MAPI
Called by: | Service providers and MAPI
Interface identifier: | IID_IMAPIAdviseSink
Pointer type: | LPMAPIADVISESINK

Vtable Order

OnNotify Responds to a notification by performing one or more tasks. The tasks performed depends on the object generating the notification and type of event.


IMAPIAdviseSink::OnNotify

The IMAPIAdviseSink::OnNotify method responds to a notification by performing one or more tasks. The tasks performed depend on the object generating the notification and type of event.

Quick Info

See IMAPIAdviseSink : IUnknown.

ULONG OnNotify(
  ULONG cNotif,
  LPNOTIFICATION lpNotifications
);

Parameters

cNotif
[in] Count of NOTIFICATION structures pointed to by the lpNotifications parameter.
lpNotifications
[in] Pointer to one or more NOTIFICATION structures that provide information about the events that have occurred.

Return Value

S_OK
The notification was processed successfully.

Remarks

The notification process begins when a client or MAPI makes a call to a service provider's Advise method to register to receive a notification of a particular type for a particular object. One of the parameters to the Advise method is a pointer to an advise sink object — an object that implements IMAPIAdviseSink. When an event occurs to the target object that corresponds to the registered notification, the service provider, either directly or indirectly through MAPI, calls the advise sink's OnNotify method.

The call to OnNotify can occur either during the MAPI call that is causing the event or at some later time. On systems that support multiple threads of execution, OnNotify can be called either on the same thread that was used for registration or on a different thread. Clients can insure that the OnNotify call is made on the same thread used to call Advise by creating the advise sink that they pass to Advise with the HrThisThreadAdviseSink function.

The lpNotifications parameter points to one or more NOTIFICATION structures — structures that describe what has changed during the event. There is a different type of NOTIFICATION structure for each type of event.

The following table lists the values that are used to represent the possible types of events and the structures associated with each value:

Notification event type Corresponding structure
fnevCriticalError
 ERROR_NOTIFICATION
fnevNewMail
 NEWMAIL_NOTIFICATION
fnevObjectCreated
 OBJECT_NOTIFICATION
fnevObjectDeleted
 OBJECT_NOTIFICATION
fnevObjectModified
 OBJECT_NOTIFICATION
fnevObjectCopied
 OBJECT_NOTIFICATION
fnevSearchComplete
 OBJECT_NOTIFICATION
fnevTableModified
 TABLE_NOTIFICATION
fnevStatusObjectModified
 STATUS_OBJECT_NOTIFICATION
fnevExtended
 EXTENDED_NOTIFICATION

For more information about setting up and stopping notifications, see the reference entries for the Advise and Unadvise methods for any of the following interfaces: IABLogon, IAddrBook, IMAPIForm, IMAPISession, IMAPITable, IMsgStore, and IMSLogon.

For general information about the notification process, see Event Notification in MAPI.

Notes to Implementers

Your OnNotify implementation will typically consist of one or more blocks of code for each type of notification you expect to receive. Within these blocks of code, perform any tasks that you deem necessary as a response to the notification. For example, suppose you register to receive fnevObjectModified notifications on a folder that is included in a dialog box display. In the block of code that you include in your OnNotify method to handle fnevObjectModified notifications, you might send a Windows message to the dialog box to request an updated display.

Do not modify or free the NOTIFICATION structure passed to OnNotify. The data in the structure is valid only until OnNotify returns.

Notes to Callers

When changes occur to multiple objects, you can notify a registered advise sink in a single call to OnNotify or in multiple calls depending on memory constraints. This is true regardless of whether the changes are the result of one method call or several. For example, a call to IMAPIFolder::CopyMessages can affect multiple messages and folders. As a message store provider, you can make one call to OnNotify with an fnevObjectModified event type for the target folder or many calls, one for each of the affected messages. Similarly, if a client makes repeated calls to IMAPIFolder::CreateMessage, these calls can be combined into one fnevObjectModified event for the folder or separated into individual fnevObjectCreated events for each of the new messages.

For more information about how and when to generate notifications, see the topics:

Event Notification in MAPI

Supporting Event Notification

See Also

HrAllocAdviseSink, HrThisThreadAdviseSink, IMAPISupport::Notify, NOTIFICATION


IMAPIContainer : IMAPIProp

The IMAPIContainer interface manages high-level operations on container objects such as address books, distribution lists, and folders. The IMAPIFolder, IABContainer, and IDistList interfaces are derived from IMAPIContainer.

Quick Info

Header file: | MAPIDEFS.H
Exposed by: | Folder, address book container, and distribution list objects
Implemented by: | Message store, address book, and remote transport providers
Called by: | Client applications
Interface identifier: | IID_IMAPIContainer
Pointer type: | LPMAPICONTAINER
Transaction model: | Abstract class, never implemented

Vtable Order

GetContentsTable | Returns a pointer to the container's contents table.
GetHierarchyTable | Returns a pointer to the container's hierarchy table.
OpenEntry | Opens an object within the container, returning an interface pointer for further access.
SetSearchCriteria | Establishes search criteria for the container.
GetSearchCriteria | Obtains the search criteria for the container.

Required properties | Access
PR_CONTAINER_HIERARCHY | Read-only
PR_CONTAINER_CONTENTS | Read-only
PR_CONTAINER_FLAGS | Read/write


IMAPIContainer::GetContentsTable

The IMAPIContainer::GetContentsTable method returns a pointer to the container's contents table.

Quick Info

See IMAPIContainer : IMAPIProp.

HRESULT GetContentsTable(
  ULONG ulFlags,
  LPMAPITABLE FAR * lppTable
);

Parameters

ulFlags
[in] Bitmask of flags that controls how the contents table is returned. The following flags can be set:
MAPI_ASSOCIATED
The container's associated contents table should be returned rather than the standard contents table. This flag is used only with folders. The messages that are included in the associated contents table were created with the MAPI_ASSOCIATED flag set in the call to IMAPIFolder::CreateMessage. Clients typically use the associated contents table to retrieve forms and views.
MAPI_DEFERRED_ERRORS
GetContentsTable can return successfully, possibly before the table is made accessible to the caller. If the table is not accessible, making a subsequent table call can result in an error.
MAPI_UNICODE
Requests that the columns containing string data be returned in the Unicode format. If the MAPI_UNICODE flag is not set, the strings should be returned in the ANSI format.
lppTable
[out] Pointer to a pointer to the contents table.

Return Values

S_OK
The contents table was successfully retrieved.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.
MAPI_E_NO_SUPPORT
The container has no contents and cannot provide a contents table.

Remarks

The IMAPIContainer::GetContentsTable method returns a pointer to the contents table of a container. A contents table contains summary information about objects within the container.

Contents tables have lengthy column sets. For a complete list of the required and optional columns in contents tables, see Contents Tables.

It is possible for some containers to have no contents. These containers return MAPI_E_NO_SUPPORT from their implementations of GetContentsTable.

Notes to Implementers

If you support a contents table for your container, you must also:

  • Support calls to the container's IMAPIProp::OpenProperty method to open the PR_CONTAINER_CONTENTS property.
  • Return PR_CONTAINER_CONTENTS in response to a call to the container's IMAPIProp::GetProps and IMAPIProp::GetPropList methods.

A remote transport provider's implementation of this method must return a pointer to an IMAPITable interface in the ppTable parameter passed into the GetContentsTable method. If your transport provider has an existing contents table, it suffices to return a pointer to it. If not, then this method must create a new IMAPITable object, populate the table with message headers (if any are available), and return a pointer to the new table. The ITableData method HrGetView is useful for generating a return value and storing the table pointer in the ppTable parameter. The contents table must support at least the following property columns:

PR_ENTRYID | PR_SENDER_NAME
PR_SENT_REPRESENTING_NAME | PR_DISPLAY_TO
PR_SUBJECT | PR_MESSAGE_CLASS
PR_MESSAGE_FLAGS | PR_MESSAGE_SIZE
PR_PRIORITY | PR_IMPORTANCE
PR_SENSITIVITY | PR_MESSAGE_DELIVERY_TIME
PR_MSG_STATUS | PR_MESSAGE_DOWNLOAD_TIME
PR_HASATTACH | PR_OBJECT_TYPE
PR_INSTANCE_KEY | PR_NORMALIZED_SUBJECT

Notes to Callers

String and binary contents table columns can be truncated. Typically, providers return 255 characters. Because you cannot know ahead of time whether or not a table includes truncated columns, assume that a column is truncated if the length of the column is either 255 or 510 bytes. You can always retrieve the full value of a truncated column if necessary from the object directly by using its entry identifier to open it and then calling the IMAPIProp::GetProps method.

Depending on the provider's implementation, restrictions and sorting operations can apply to an entire string or to the truncated version of that string.

See Also

IMAPIProp::GetPropList, IMAPIProp::GetProps, IMAPIProp::OpenProperty, IMAPITable : IUnknown, PR_CONTAINER_CONTENTS


IMAPIContainer::GetHierarchyTable

The IMAPIContainer::GetHierarchyTable method returns a pointer to the container's hierarchy table.

Quick Info

See IMAPIContainer : IMAPIProp.

HRESULT GetHierarchyTable(
  ULONG ulFlags,
  LPMAPITABLE FAR * lppTable
);

Parameters

ulFlags
[in] Bitmask of flags that controls how information is returned in the table. The following flags can be set:
CONVENIENT_DEPTH
Fills the hierarchy table with containers from multiple levels. If CONVENIENT_DEPTH is not set, the hierarchy table contains only the container's immediate child containers.
MAPI_DEFERRED_ERRORS
GetHierarchyTable can return successfully, possibly before the table is made accessible to the caller. If the table is not accessible, making a subsequent table call can result in an error.
MAPI_UNICODE
Requests that the columns containing string data be returned in Unicode format. If the MAPI_UNICODE flag is not set, the strings should be returned in ANSI format.
lppTable
[out] Pointer to a pointer to the hierarchy table.

Return Values

S_OK
The hierarchy table was successfully retrieved.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.
MAPI_E_NO_SUPPORT
The container has no child containers and cannot provide a hierarchy table.

Remarks

The IMAPIContainer::GetHierarchyTable method returns a pointer to the hierarchy table of a container. A hierarchy table holds summary information about the child containers within the container. Folder hierarchy tables hold information about child folders; address book hierarchy tables hold information about child address book containers and distribution lists.

It is possible for some containers to have no child containers. These containers return MAPI_E_NO_SUPPORT from their implementations of GetHierarchyTable.

When the CONVENIENT_DEPTH flag is set, each row in the hierarchy table also includes the PR_DEPTH property as a column. PR_DEPTH indicates the level of each container relative to the container implementing the table. The implementing container's immediate child containers are at depth zero, child containers within the zero depth containers are at depth one, and so on. The values of PR_DEPTH increase sequentially as the hierarchy of levels deepens.

For a complete list of required and optional columns in hierarchy tables, see Hierarchy Tables.

Notes to Implementers

If you support a hierarchy table for your container, you must also:

  • Support a call to the container's IMAPIProp::OpenProperty method to open the PR_CONTAINER_HIERARCHY property.
  • Return PR_CONTAINER_HIERARCHY from a call to the container's IMAPIProp::GetProps or IMAPIProp::GetPropList method.

Notes to Callers

String and binary contents table columns can be truncated. Typically, providers return 255 characters. Because you cannot know ahead of time whether or not a table includes truncated columns, assume that a column is truncated if the length of the column is either 255 or 510 bytes. You can always retrieve the full value of a truncated column if necessary from the object directly by using its entry identifier to open it and then calling the IMAPIProp::GetProps method.

Depending on the provider's implementation, restrictions and sorting operations can apply to an entire string or to the truncated version of that string.

See Also

IMAPIProp::GetPropList, IMAPIProp::GetProps, IMAPITable : IUnknown, PR_CONTAINER_HIERARCHY


IMAPIContainer::GetSearchCriteria

The IMAPIContainer::GetSearchCriteria method obtains the search criteria for the container.

Quick Info

See IMAPIContainer : IMAPIProp.

HRESULT GetSearchCriteria(
  ULONG ulFlags,
  LPSRestriction FAR * lppRestriction,
  LPENTRYLIST FAR * lppContainerList,
  ULONG FAR * lpulSearchState
);

Parameters

ulFlags
[in] Bitmask of flags that controls the type of the passed-in strings. The following flag can be set:
MAPI_UNICODE
The passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppRestriction
[out] Pointer to a pointer to an SRestriction structure defining the search criteria. If a client application passes NULL in the lppRestriction parameter, GetSearchCriteria does not return an SRestriction structure.
lppContainerList
[out] Pointer to a pointer to an array of entry identifiers representing containers to be included in the search. If a client passes NULL in the lppContainerList parameter, GetSearchCriteria does not return an array of entry identifiers.
lpulSearchState
[out] Pointer to a bitmask of flags used to indicate the current state of the search. If a client passes NULL in the lpulSearchState parameter, GetSearchCriteria does not return any flags. The following flags can be set for lpulSearchState:
SEARCH_FOREGROUND
The search is running at high priority relative to other searches. If this flag is not set, the search is running at normal priority relative to other searches.
SEARCH_REBUILD
The search is in the CPU-intensive mode of its operation, attempting to locate messages that match the criteria. If this flag is not set, the CPU-intensive part of the search's operation is over. This flag only has meaning if the search is active — that is, if the SEARCH_RUNNING flag is set.
SEARCH_RECURSIVE
The search is looking in specified containers and all of their child containers for matching entries. If this flag is not set, only the containers explicitly included in the last call to the IMAPIContainer::SetSearchCriteria method are being searched.
SEARCH_RUNNING
The search is active and the container's contents table is being updated to reflect changes in the message store or address book. If this flag is not set, the search is inactive and the contents table is static.

Return Values

S_OK
The search criteria was successfully obtained.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.
MAPI_E_NOT_INITIALIZED
Search criteria were never established for the container.

Remarks

The IMAPIContainer::GetSearchCriteria method obtains the search criteria for a container that supports searches, typically a search-results folder. Search criteria are created by calling a container's IMAPIContainer::SetSearchCriteria method.

Notes to Implementers

Address book containers only need to support GetSearchCriteria if they provide the advanced search capabilities associated with the PR_SEARCH property. For more information on implementing the advanced search feature for address book containers, see Implementing Advanced Searching.

Notes to Callers

When you are finished with the data structures pointed to by the lppRestriction and lppContainerList parameters, call MAPIFreeBuffer to release the structures — one call to release each structure.

See Also

IMAPIContainer::SetSearchCriteria, IMAPIFolder::CreateFolder, MAPIFreeBuffer, PR_SEARCH


IMAPIContainer::OpenEntry

The IMAPIContainer::OpenEntry method opens an object within the container, returning an interface pointer for further access.

Quick Info

See IMAPIContainer : IMAPIProp.

HRESULT OpenEntry(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  LPCIID lpInterface,
  ULONG ulFlags,
  ULONG FAR * lpulObjType,
  LPUNKNOWN FAR * lppUnk
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the object to open. If lpEntryID is set to NULL, the top-level container in the container's hierarchy is opened.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the object. Passing NULL results in the identifier for the object's standard interface being returned. For messages, the standard interface is IMessage; for folders, it is IMAPIFolder. The standard interfaces for address book objects are IDistList for a distribution list and IMailUser for a messaging user.
ulFlags
[in] Bitmask of flags that controls how the object is opened. The following flags can be used:
MAPI_BEST_ACCESS
Requests that the object be opened with the maximum network permissions allowed for the user and the maximum client application access. For example, if the client has read/write access, the object should be opened with read/write access; if the client has read-only access, the object should be opened with read-only access.
MAPI_DEFERRED_ERRORS
Allows OpenEntry to return successfully, possibly before the object is fully accessible to the calling client. If the object is not accessible, making a subsequent object call can result in an error.
MAPI_MODIFY
Requests read/write access. By default, objects are opened with read-only access, and clients should not work on the assumption that read/write access has been granted.
lpulObjType
[out] Pointer to the opened object's type.
lppUnk
[out] Pointer to a pointer to the interface implemention to use to access the open object.

Return Values

S_OK
The object was successfully opened.
MAPI_E_NO_ACCESS
Either the user has insufficient permissions to open the object or an attempt was made to open a read-only object with read/write access.
MAPI_E_NOT_FOUND
The entry identifier specified by lpEntryID does not represent an object.
MAPI_E_UNKNOWN_ENTRYID
The entry identifier in the lpEntryID parameter is not of a format recognized by the container.

Remarks

The IMAPIContainer::OpenEntry method opens an object within a container and returns a pointer to an interface implementation to use for further access.

Notes to Callers

Because service providers are not required to return an interface implementation of the type specified by the interface identifier in lpInterface, check the value pointed to by the lpulObjType parameter. If necessary, cast the pointer returned in lppUnk to a pointer of the appropriate type.

By default, service providers open objects with read-only access unless you set either the MAPI_MODIFY or MAPI_BEST_ACCESS flag. When one of these flags is set, service providers attempt to return a modifiable object. Do not assume that because you set the MAPI_MODIFY flag, for example, that the opened object has read/write access. Either plan for the possibility of a subsequent modification to fail or retrieve the object's PR_ACCESS_LEVEL property to determine the access level granted by OpenEntry.


IMAPIContainer::SetSearchCriteria

The IMAPIContainer::SetSearchCriteria method establishes search criteria for the container.

Quick Info

See IMAPIContainer : IMAPIProp.

HRESULT SetSearchCriteria(
  LPSRestriction lpRestriction,
  LPENTRYLIST lpContainerList,
  ULONG ulSearchFlags
);

Parameters

lpRestriction
[in] Pointer to an SRestriction structure defining the search criteria. If NULL is passed in the lpRestriction parameter, then the search criteria used most recently for this container are used again. NULL should not be passed in lpRestriction for the container's first search.
lpContainerList
[in] Pointer to an array of entry identifiers representing containers to be included in the search. If a client passes NULL in the lpContainerList parameter, then the entry identifiers used most recently to search this container are used for the new search. A client should not pass NULL in lpContainerList for the first search within a container.
ulSearchFlags
[in] Bitmask of flags that controls how the search is performed. The following flags can be set:
BACKGROUND_SEARCH
The search should run at normal priority relative to other searches. This flag cannot be set at the same time as the FOREGROUND_SEARCH flag.
FOREGROUND_SEARCH
The search should run at high priority relative to other searches. This flag cannot be set at the same time as the BACKGROUND_SEARCH flag.
RECURSIVE_SEARCH
The search should include the containers specified in the lpContainerList parameter and all of their child containers. This flag cannot be set at the same time as the SHALLOW_SEARCH flag.
RESTART_SEARCH
The search should be initiated, if this is the first call to SetSearchCriteria, or restarted, if the search is inactive. This flag cannot be set at the same time as the STOP_SEARCH flag.
SHALLOW_SEARCH
The search should only look in the containers specified in the lpContainerList parameter for matching entries. This flag cannot be set at the same time as the RECURSIVE_SEARCH flag.
STOP_SEARCH
The search should be aborted. This flag cannot be set at the same time as the RESTART_SEARCH flag.

Return Values

S_OK
The search criteria was successfully set.
MAPI_E_TOO_COMPLEX
The service provider does not support the search criteria specified.

Remarks

The IMAPIContainer::SetSearchCriteria method establishes search criteria for a container that supports searches, typically a search-results folder. A search-results folder contains links to the messages that meet the search criteria; the actual messages are still stored in their original locations. The only unique data contained in a search-results folder is its contents table. The contents table of a search-results folder has the merged contents of the message store after the search restriction has been applied.

A search operation only works on this merged contents table; it does not search through other search-results folders. The search results only return the messages that match the search criteria; the folder hierarchy is not returned.

Control is returned to the client when the search has finished.

Notes to Implementers

Address book containers establish search critieria by applying restrictions to their contents tables. For more information about search criteria and address book containers, see Implementing Advanced Searching.

You should support open, copy, move, and delete operations on the messages within search-results folders, not on the search-results folder itself. Do not allow messages to be created within or copied into a search-results folder.

Notes to Callers

To search for message recipients, set lpRestriction to point to a subobject restriction with the ulSubObject member in the SSubRestriction structure set to PR_MESSAGE_RECIPIENTS. To search for attachments, set the ulSubObject member to PR_MESSAGE_ATTACHMENTS. Set the lpRes member to point to a property restriction describing the search criteria for the recipients or attachments.

For example, to look for file attachments with the extension .MSS, set ulSubObject to PR_MESSAGE_ATTACHMENTS and lpRes to a property restriction that matches PR_ATTACH_EXTENSION with MSS.

Setting the FOREGROUND_SEARCH flag in the ulSearchFlags parameter might cause a performance degradation.

You can use SetSearchCriteria to change the search criteria of a search already in progress. You can specify new restrictions, new lists of folders to search, and a new search priority, such as upgrading a search to a higher priority. Changes in search priority do not cause an existing search to restart, but other changes to search criteria can.

When you are through using a search-results folder, you can either delete the folder or let it remain open for later use. If you do delete the search-results folder, only message links are deleted. The actual messages remain in their parent folders.

For more information on search-results folders, see Search-Results Folders.

See Also

IMAPIContainer::GetContentsTable, IMAPIContainer::OpenEntry, IMAPIFolder::CreateFolder, IMAPIFolder : IMAPIContainer, SPropertyRestriction, SRestriction, SSubRestriction


IMAPIControl : IUnknown

The IMAPIControl interface is used to enable and disable a button control and to perform tasks when a user of a client application clicks the enabled control. Service providers implement control objects to create custom buttons on dialog boxes, such as configuration property sheets, that are defined with display tables.

For more information on working with display tables and control objects, see Display Tables.

Quick Info

Header file: | MAPIDEFS.H
Exposed by: | Control objects
Implemented by: | Service providers
Called by: | MAPI
Interface identifier: | IID_IMAPIControl
Pointer type: | LPMAPICONTROL

Vtable Order

GetLastError | Returns a MAPIERROR structure containing information about the previous button control error.
Activate | Performs a task — such as displaying a dialog box or starting a programmatic operation — when the button control is clicked by a user of a client application.
GetState | Retrieves a value that indicates whether the button control is enabled or disabled.


IMAPIControl::Activate

The IMAPIControl::Activate method performs a task — such as displaying a dialog box or starting a programmatic operation — when the button control is clicked by a user of a client application.

Quick Info

See IMAPIControl : IUnknown.

HRESULT Activate(
  ULONG ulFlags,
  ULONG ulUIParam
);

Parameters

ulFlags
Reserved; must be zero.
ulUIParam
[in] Handle of the parent window for the dialog box on which the button control appears.

Return Values

S_OK
The button control was successfully activated.

Remarks

The IMAPIControl::Activate method performs tasks following a user's click of the button control. After the click occurs, as part of the processing of the display table, MAPI makes a call to Activate after first calling IMAPIControl::GetState to determine if the button is enabled.

For more information about implementing Activate and the other IMAPIControl methods, see Implementing a Control Object.

See Also

IMAPIControl::GetState


IMAPIControl::GetLastError

The IMAPIControl::GetLastError method returns a MAPIERROR structure containing information about the previous button control error.

Quick Info

See IMAPIControl : IUnknown.

HRESULT GetLastError(
  HRESULT hResult,
  ULONG ulFlags,
  LPMAPIERROR FAR * lppMAPIError
);

Parameters

hResult
[in] HRESULT data type containing the error value generated in the previous method call.
ulFlags
[in] Bitmask of flags that controls the type of the returned strings. The following flag can be set:
MAPI_UNICODE
The strings in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppMAPIError
[out] Pointer to a pointer to a MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if the provider cannot supply a MAPIERROR structure with appropriate information.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Remarks

Service providers implement the IMAPIControl::GetLastError method to supply information about a prior method call that failed. MAPI can provide users with detailed information about the error by displaying the data from the MAPIERROR structure in a message or dialog box.

Notes to Implementers

It is not required that you have information to place in the MAPIERROR structure for every error. It may not be possible to determine what the previous error was. If you have information, return S_OK and the appropriate data in the MAPIERROR structure. If no information is available, return S_OK and a pointer to NULL for the lppMAPIError parameter.

For more information about the GetLastError method, see Using Extended Errors.

See Also

MAPIERROR, MAPIFreeBuffer


IMAPIControl::GetState

The IMAPIControl::GetState method retrieves a value that indicates whether the button control is enabled or disabled.

Quick Info

See IMAPIControl : IUnknown.

HRESULT GetState(
  ULONG ulFlags,
  ULONG FAR * lpulState
);

Parameters

ulFlags
Reserved; must be zero.
lpulState
[out] Pointer to a value indicating the state of the button control. One of the following values can be set:
MAPI_DISABLED
The button control is disabled and cannot be clicked.
MAPI_ENABLED
The button control is enabled and can be clicked.

Return Values

S_OK
The state of the button control was successfully retrieved.

Remarks

Service providers implement the IMAPIControl::GetState method to provide MAPI with the state of a button control. If enabled, the button can respond to a mouse click or key press. If disabled, the button appears dimmed and is incapable of responding to a mouse click or key press.

For more information about implementing GetState and the other IMAPIControl methods, see Implementing a Control Object.

See Also

IMAPIControl::Activate


IMAPIFolder : IMAPIContainer

The IMAPIFolder interface is used to perform operations on the messages and subfolders in a folder.

Quick Info

Header file: | MAPIDEFS.H
Exposed by: | Folder objects
Implemented by: | Message store providers
Called by: | Client applications and MAPI
Interface identifier: | IID_IMAPIFolder
Pointer type: | LPMAPIFOLDER
Transaction model: | Nontransacted

Vtable Order

CreateMessage | Creates a new message.
CopyMessages | Copies or moves one or more messages.
DeleteMessages | Deletes one or more messages.
CreateFolder | Creates a new subfolder.
CopyFolder | Copies or moves a subfolder.
DeleteFolder | Deletes a subfolder.
SetReadFlags | Sets or clears the MSGFLAG_READ flag in the PR_MESSAGE_FLAGS property of one or more of the folder's messages and manages the sending of read reports.
GetMessageStatus | Obtains a message's status.
SetMessageStatus | Sets a message's status.
SaveContentsSort | Sets the default sort order for the contents table.
EmptyFolder | Removes all of the subfolders and messages without deleting the folder itself.

Required properties | Access
PR_DISPLAY_NAME | Read/write
PR_ENTRYID | Read-only
PR_FOLDER_TYPE | Read/write
PR_OBJECT_TYPE | Read-only
PR_PARENT_ENTRYID | Read-only
PR_RECORD_KEY | Read-only
PR_STORE_ENTRYID | Read-only
PR_STORE_RECORD_KEY | Read-only


IMAPIFolder::CopyFolder

The IMAPIFolder::CopyFolder method copies or moves a subfolder.

Quick Info

See IMAPIFolder : IMAPIContainer.

HRESULT CopyFolder(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  LPCIID lpInterface,
  LPVOID lpDestFolder,
  LPTSTR lpszNewFolderName,
  ULONG ulUIParam,
  LPMAPIPROGRESS lpProgress,
  ULONG ulFlags
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the subfolder to copy or move.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the folder pointed to by the lpDestFolder parameter. Passing NULL results in the service provider returning the standard folder interface, IMAPIFolder. Valid values for lpInterface include IID_IUnknown, IID_IMAPIProp, IID_IMAPIContainer, or IID_IMAPIFolder.
lpDestFolder
[in] Pointer to the open folder to receive the copied or moved subfolder.
lpszNewFolderName
[in] Pointer to the name of the copied or moved folder in its new destination. If lpszNewFolderName is set to NULL, the name of the source subfolder is used for the name of the destination folder.
ulUIParam
[in] Handle of the parent window for the progress indicator. The ulUIParam parameter is ignored unless the FOLDER_DIALOG flag in the ulFlags parameter is set.
lpProgress
[in] Pointer to a progress object for displaying a progress indicator. If NULL is passed in lpProgress, the message store provider displays a progress indicator using the MAPI progress object implementation. The lpProgress parameter is ignored unless the FOLDER_DIALOG flag is set in ulFlags.
ulFlags
[in] Bitmask of flags that controls the copy or move operation. The following flags can be set:
COPY_SUBFOLDERS
All of the subfolders in the subfolder to be copied should also be copied. When COPY_SUBFOLDERS is not set for a copy operation, only the subfolder identified by lpEntryID is copied. With a move operation, the COPY_SUBFOLDERS behavior is the default regardless of whether the flag is set.
FOLDER_DIALOG
Requests the display of a progress indicator.
FOLDER_MOVE
The subfolder is to be moved rather than copied. If FOLDER_MOVE is not set, the subfolder is copied.
MAPI_DECLINE_OK
Informs the message store provider that if it implements CopyFolder by calling its support object's IMAPISupport::DoCopyTo or IMAPISupport::DoCopyProps method, it should instead immediately return MAPI_E_DECLINE_COPY from CopyFolder.
MAPI_UNICODE
The name of the destination folder is in Unicode format. If the MAPI_UNICODE flag is not set, the folder name is in ANSI format.

Return Values

S_OK
The specified folder has been successfully copied or moved.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the message store provider does not support Unicode, or MAPI_UNICODE was not set and the message store provider only supports Unicode.
MAPI_E_COLLISION
The name of the folder being moved or copied is the same as that of a subfolder in the destination folder. The message store provider requires that folder names be unique.
MAPI_E_DECLINE_COPY
The provider implements this method by calling a support object method and the caller has passed the MAPI_DECLINE_OK flag.
MAPI_E_FOLDER_CYCLE
The source folder directly or indirectly contains the destination folder. Significant work might have been performed before this condition was discovered so the source and destination folder might be partially modified.
MAPI_W_PARTIAL_COMPLETION
The call succeeded, but not all entries were successfully copied. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IMAPIFolder::CopyFolder method copies or moves a subfolder from one location to another. The subfolder being copied or moved is added to the destination folder as a subfolder.

Notes to Implementers

When the copy or move operation involves more than one folder, as indicated by the COPY_SUBFOLDERS flag being set, perform the operation as completely as possible for each folder. Sometimes one of the folders to be moved or copied does not exist or has already been moved or copied elsewhere. Do not stop the operation prematurely unless a failure occurs that is beyond your control, such as running out of memory, running out of disk space, or corruption in the message store.

Try to retain all message entry identifiers in the copied messages. Preserving entry identifiers is not required, but it is recommended.

Notes to Callers

Expect these return values under the following conditions:

Condition | Return value
CopyFolder has successfully copied or moved every message and subfolder. | S_OK
CopyFolder was unable to successfully copy or move every message and subfolder. | MAPI_W_PARTIAL_COMPLETION or MAPI_E_NOT_FOUND
CopyFolder was unable to complete. | Any error value except MAPI_E_NOT_FOUND

When CopyFolder is unable to complete, do not assume that no work was done. CopyFolder might have been able to copy or move one or more of the messages and subfolders before encountering the error.

If an entry identifier for a folder that doesn't exist is passed in lpEntryID, CopyFolder returns MAPI_W_PARTIAL_COMPLETION or MAPI_E_NOT_FOUND, depending on the message store's implementation.

Depending on the message store provider, the entry identifier of the original message may or may not be preserved in the copied message. MAPI recommends that entry identifiers be preserved whenever possible, but it is not a requirement. You can generally depend on the following:

  • When moving a folder between two different types of message stores, the entry identifier is guaranteed to change.
  • When moving a folder between two message stores of the same type, the entry identifier almost always changes.
  • When moving a folder to another location within the same message store, the entry identifier might or might not change, depending on the message store provider.


IMAPIFolder::CopyMessages

The IMAPIFolder::CopyMessages method copies or moves one or more messages.

Quick Info

See IMAPIFolder : IMAPIContainer.

HRESULT CopyMessages(
  LPENTRYLIST lpMsgList,
  LPCIID lpInterface,
  LPVOID lpDestFolder,
  ULONG ulUIParam,
  LPMAPIPROGRESS lpProgress,
  ULONG ulFlags
);

Parameters

lpMsgList
[in] Pointer to an array of ENTRYLIST structures that identify the message or messages to copy or move.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the destination folder pointed to by the lpDestFolder parameter. Passing NULL results in the service provider returning the standard folder interface, IMAPIFolder. Clients must pass NULL. Other callers can set the lpInterface parameter to IID_IUnknown, IID_IMAPIProp, IID_IMAPIContainer, or IID_IMAPIFolder.
lpDestFolder
[in] Pointer to the open folder to receive the copied or moved messages.
ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays. The ulUIParam parameter is ignored unless the client sets the MESSAGE_DIALOG flag in the ulFlags parameter and passes NULL in the lpProgress parameter.
lpProgress
[in] Pointer to a progress object for displaying a progress indicator. If NULL is passed in lpProgress, the message store provider displays a progress indicator using the MAPI progress object implementation. The lpProgress parameter is ignored unless the MESSAGE_DIALOG flag is set in ulFlags.
ulFlags
[in] Bitmask of flags that controls how the copy or move operation is accomplished. The following flags can be set:
MAPI_DECLINE_OK
Informs the message store provider to immediately return MAPI_E_DECLINE_COPY if it implements CopyMessage by calling the support object's IMAPISupport::DoCopyTo or IMAPISupport::DoCopyProps method.
MESSAGE_DIALOG
Displays a progress indicator as the operation proceeds.
MESSAGE_MOVE
The message or messages are to be moved rather than copied. If MESSAGE_MOVE is not set, the messages are copied.

Return Values

S_OK
The message or messages have been successfully copied or moved.
MAPI_E_DECLINE_COPY
The provider implements this method by calling a support object method and the caller has passed the MAPI_DECLINE_OK flag.
MAPI_W_PARTIAL_COMPLETION
The call succeeded, but not all entries were successfully copied or moved. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IMAPIFolder::CopyMessages method copies or moves messages to another folder.

Messages that are open with read/write access can be moved or copied.

Notes to Implementers

If you are copying messages to another message store without using the IMAPISupport::CopyMessages method, you must first call IMAPIFolder::SetReadFlags with the GENERATE_RECEIPT_ONLY flag set. The receiving message store is not responsible for generating read reports for the copied or moved messages. If you are calling IMAPISupport::CopyMessages to implement IMAPIFolder::CopyMessages, do not make the SetReadFlags call. MAPI will take care of it.

Move or copy the messages in any order and generate read status reports in any order. That is, you can finish copying messages before generating any of the read status reports or send the reports before beginning the copy. However, read reports should be sent for all messages to be copied, regardless of whether or not the copy is successful.

When the copy or move operation involves more than one message, perform the operation as completely as possible. Do not stop the operation prematurely unless a failure occurs that is beyond your control, such as running out of memory, running out of disk space, or corruption in the message store.

Try to maintain entry identifiers across move or copy operations.

Send notifications when moving or copying messages so that clients are forewarned that their calls to the messages' IMAPIProp::SaveChanges methods may fail.

Do not include a message's status in the copy or move operation. Moving or copying a message status greatly affects performance.

Notes to Callers

Use CopyMessages for populating search-results folders, where messages are often grouped by parent folder.

Expect these return values under the following conditions:

Condition | Return value
CopyMessages has successfully copied or moved every message. | S_OK
CopyMessages was unable to successfully copy or move every message. | MAPI_W_PARTIAL_COMPLETION
CopyMessages was unable to complete. | Any error value

When CopyMessages is unable to complete, do not assume that no work was done. CopyMessages might have been able to copy or move one or more messages before encountering the error.


IMAPIFolder::CreateFolder

The IMAPIFolder::CreateFolder method creates a new subfolder.

Quick Info

See IMAPIFolder : IMAPIContainer.

HRESULT CreateFolder(
  ULONG ulFolderType,
  LPTSTR lpszFolderName,
  LPTSTR lpszFolderComment,
  LPCIID lpInterface,
  ULONG ulFlags,
  LPMAPIFOLDER FAR * lppFolder
);

Parameters

ulFolderType
[in] The type of folder to create. One of the following values can be passed:
FOLDER_GENERIC
A generic folder should be created.
FOLDER_SEARCH
A search-results folder should be created.
lpszFolderName
[in] Pointer to a string containing the name for the new folder. This name is the basis for the new folder's PR_DISPLAY_NAME property.
lpszFolderComment
[in] Pointer to a string containing a comment associated with the new folder. This string becomes the value of the new folder's PR_COMMENT property. If NULL is passed, the folder has no initial comment.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the new folder. Passing NULL results in the message store provider returning the standard folder interface, IMAPIFolder. Clients must pass NULL. Other callers can set the lpInterface parameter to IID_IUnknown, IID_IMAPIProp, IID_IMAPIContainer, or IID_IMAPIFolder.
ulFlags
[in] Bitmask of flags that controls how the folder is created. The following flags can be set:
MAPI_DEFERRED_ERRORS
Allows CreateFolder to return successfully, possibly before the new folder is fully accessible to the calling client. If the new folder is not accessible, making a subsequent call to it can result in an error.
MAPI_UNICODE
The passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
OPEN_IF_EXISTS
Allows the method to succeed — even if the folder named in the lpszFolderName parameter already exists — by opening the existing folder with that name. Note that message store providers that allow sibling folders to have the same name might fail to open an existing folder if more than one exists with the supplied name.
lppFolder
[out] Pointer to a pointer to the newly created folder.

Return Values

S_OK
The new folder has been successfully created or opened, if the OPEN_IF_EXISTS flag is set.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.
MAPI_E_COLLISION
A folder with the name given in the lpszFolderName parameter already exists. Folder names must be unique.

Remarks

The IMAPIFolder::CreateFolder method creates a subfolder in the current folder and assigns an entry identifier to the new folder.

Notes to Callers

When CreateFolder returns, be aware that the entry identifier for the new folder might not be available. Some message store providers do not make entry identifiers available until after you have called the new folder's IMAPIProp::SaveChanges method to permanently save it. This is especially true if you have set the MAPI_DEFERRED_ERRORS flag.

Be aware that some message store providers always point lppFolder to the folder's standard interface, regardless of the value that you pass in for the lpInterface parameter. Because the interface pointer that is returned might not be of the type that you expect, call the new folder's IMAPIProp::GetProps method to retrieve the PR_OBJECT_TYPE property. If necessary, cast the pointer to a more appropriate type before making other calls.

Most message store providers require the name of the new folder to be unique with respect to the names of its sibling folders. Be able to handle the MAPI_E_COLLISION error value, which is returned if this rule is not followed.

To determine the entry identifier of the newly created folder, call the new folder's IMAPIProp::GetProps method to retrieve its PR_ENTRYID property.

See Also

IMAPIProp::GetProps


IMAPIFolder::CreateMessage

The IMAPIFolder::CreateMessage method creates a new message.

Quick Info

See IMAPIFolder : IMAPIContainer.

HRESULT CreateMessage(
  LPCIID lpInterface,
  ULONG ulFlags,
  LPMESSAGE FAR * lppMessage
);

Parameters

lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the new message. Valid interface identifiers include IID_IUnknown, IID_IMAPIProp, IID_IMAPIContainer, and IID_IMAPIFolder. Passing NULL results in the message store provider returning the standard message interface, IMessage.
ulFlags
[in] Bitmask of flags that controls how the message is created. The following flags can be set:
MAPI_ASSOCIATED
The message to be created should be included in the associated contents table rather than the standard contents table. Associated messages typically contain invisible data, such as view descriptors.
MAPI_DEFERRED_ERRORS
CreateMessage is allowed to succeed even if the create operation has not fully completed. This implies that the new message might not be immediately accessible to the caller.
lppMessage
[out] Pointer to a pointer to the newly created message.

Return Values

S_OK
The message was successfully created.

Remarks

The IMAPIFolder::CreateMessage method creates a new message with generic or associated content and assigns an entry identifier. The entry identifier is made up of a part that represents the message store provider and a part that represents the individual message.

Notes to Implementers

You can choose whether to set all of the required message properties in CreateMessage or in the message's IMAPIProp::SaveChanges method. You do not need to make these properties available until a successful save has occurred.

For more information on working with associated information, see Folder Associated Information Tables and Contents Tables.

Notes to Callers

Some message store providers allow the entry identifier of the new message to be available immediately after CreateMessage returns; others delay its availability until the message has been saved. Because not all message store providers generate an entry identifier for a new message until you have called the message's IMAPIProp::SaveChanges method, you may not be able to access the entry identifier when CreateMessage returns. Also, the new message may not be included in the folder's contents table until the save occurs.

Expect the entry identifier assigned to the new message to be unique not only within the current message store, but most likely across all of the message stores that are open concurrently. One exception to this general rule occurs when multiple entries for a message store appear in the profile, causing the message store to be opened multiple times and entry identifiers to be duplicated.

To create an outgoing message, call the Outbox folder's IMAPIFolder::CreateMessage method.

If you delete a folder containing a new message before the message is saved, the results are undefined.

See Also

IMAPIProp::SaveChanges


IMAPIFolder::DeleteFolder

The IMAPIFolder::DeleteFolder method removes a subfolder.

Quick Info

See IMAPIFolder : IMAPIContainer.

HRESULT DeleteFolder(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  ULONG ulUIParam,
  LPMAPIPROGRESS lpProgress,
  ULONG ulFlags
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the subfolder to delete.
ulUIParam
[in] Handle of the parent window for the progress indicator. The ulUIParam parameter is ignored unless the FOLDER_DIALOG flag is set in the ulFlags parameter.
lpProgress
[in] Pointer to a progress object for displaying a progress indicator. If NULL is passed in lpProgress, the message store provider displays a progress indicator using the MAPI progress object implementation. The lpProgress parameter is ignored unless the FOLDER_DIALOG flag is set in ulFlags.
ulFlags
[in] Bitmask of flags that controls the deletion of the subfolder. The following flags can be set:
DEL_FOLDERS
All subfolders of the subfolder pointed to by lpEntryID should be deleted.
DEL_MESSAGES
All messages in the subfolder pointed to by lpEntryID should be deleted.
FOLDER_DIALOG
A progress indicator should be displayed while the operation proceeds.

Return Values

S_OK
The specified folder has been successfully deleted.
MAPI_E_HAS_FOLDERS
The subfolder being deleted contains subfolders, and the DEL_FOLDERS flag was not set. The subfolder was not deleted.
MAPI_E_HAS_MESSAGES
The subfolder being deleted contains messages, and the DEL_MESSAGES flag was not set. The subfolder was not deleted.
MAPI_W_PARTIAL_COMPLETION
The call succeeded, but not all of the entries were successfully deleted. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IMAPIFolder::DeleteFolder method deletes a subfolder. Folders to be deleted must be located in the folder designated as the special wastebasket folder, typically the Deleted Items folder in the IPM subtree. By default, DeleteFolder only operates on empty folders, but it can be used successfully on non-empty folders by setting two flags: DEL_FOLDERS and DEL_MESSAGES. Only empty folders or folders that set both the DEL_FOLDERS and DEL_MESSAGES flags on the DeleteFolder call can be deleted. DEL_FOLDERS enables all of the folder's subfolders to be removed; DEL_MESSAGES enables all of the folder's messages to be removed.

Notes to Implementers

When the delete operation involves more than one folder, perform the operation as completely as possible for each folder. Sometimes one of the folders to be deleted does not exist or has been moved or copied elsewhere. Do not stop the operation prematurely unless a failure occurs that is beyond your control, such as running out of memory, running out of disk space, or corruption in the message store.

During a DeleteFolder call, messages being processed by the MAPI spooler are not deleted; they are left in their parent folders. Do not call the IMsgStore::AbortSubmit method for these messages.

Notes to Callers

Expect these return values under the following conditions:

Condition | Return value
DeleteFolder has successfully deleted every message and subfolder. | S_OK
DeleteFolder was unable to successfully delete every message and subfolder. | MAPI_W_PARTIAL_COMPLETION or MAPI_E_NOT_FOUND
DeleteFolder was unable to complete. | Any error value except MAPI_E_NOT_FOUND

When DeleteFolder is unable to complete, do not assume that no work was done. DeleteFolder might have been able to delete one or more of the messages and subfolders before encountering the error.

If one or more subfolders cannot be deleted, DeleteFolder returns MAPI_W_PARTIAL_COMPLETION or MAPI_E_NOT_FOUND, depending on the message store provider's implementation.


IMAPIFolder::DeleteMessages

The IMAPIFolder::DeleteMessages method deletes one or more messages.

Quick Info

See IMAPIFolder : IMAPIContainer.

HRESULT DeleteMessages(
  LPENTRYLIST lpMsgList,
  ULONG ulUIParam,
  LPMAPIPROGRESS lpProgress,
  ULONG ulFlags
);

Parameters

lpMsgList
[in] Pointer to an ENTRYLIST structure that contains the number of messages to delete and an array of ENTRYID structures identifying the messages.
ulUIParam
[in] Handle of the parent window for the progress indicator. The ulUIParam parameter is ignored unless the MESSAGE_DIALOG flag is set in the ulFlags parameter.
lpProgress
[in] Pointer to a progress object for displaying a progress indicator. If NULL is passed in lpProgress, the message store provider displays a progress indicator using the MAPI progress object implementation. The lpProgress parameter is ignored unless the MESSAGE_DIALOG flag is set in ulFlags.
ulFlags
[in] Bitmask of flags that controls how the messages are deleted. The following flag can be set:
MESSAGE_DIALOG
Displays a progress indicator as the operation proceeds.

Return Values

S_OK
The specified message or messages were successfully deleted.
MAPI_W_PARTIAL_COMPLETION
The call succeeded, but not all of the messages were successfully deleted. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IMAPIFolder::DeleteMessages method deletes messages from a folder. Messages that do not exist, that have been moved elsewhere, that are open with read/write access, or that are currently submitted cannot be deleted.

Notes to Implementers

When the delete operation involves more than one message, perform the operation as completely as possible for each folder, even if one or more of the messages cannot be deleted. Do not stop the operation prematurely unless a failure occurs that is beyond your control, such as running out of memory, running out of disk space, or corruption in the message store.

During a DeleteMessages call, messages being processed by the MAPI spooler are not deleted; they are left in their parent folders. Do not call the IMsgStore::AbortSubmit method for these messages.

Notes to Callers

Expect these return values under the following conditions:

Condition | Return value
DeleteMessages has successfully deleted every message. | S_OK
DeleteMessages was unable to successfully delete every message and subfolder. | MAPI_W_PARTIAL_COMPLETION or MAPI_E_NOT_FOUND
DeleteMessages was unable to complete. | Any error value except MAPI_E_NOT_FOUND

When DeleteMessages is unable to complete, do not assume that no work was done. DeleteMessages might have been able to delete one or more of the messages before encountering the error.

DeleteMessages returns MAPI_W_PARTIAL_COMPLETION or MAPI_E_NOT_FOUND, depending on the message store's implementation.


IMAPIFolder::EmptyFolder

The IMAPIFolder::EmptyFolder method deletes all messages and subfolders from a folder without deleting the folder itself.

Quick Info

See IMAPIFolder : IMAPIContainer.

HRESULT EmptyFolder(
  ULONG ulUIParam,
  LPMAPIPROGRESS lpProgress,
  ULONG ulFlags
);

Parameters

ulUIParam
[in] Handle of the parent window for the progress indicator. The ulUIParam parameter is ignored unless the FOLDER_DIALOG flag is set in the ulFlags parameter.
lpProgress
[in] Pointer to a progress object for displaying a progress indicator. If NULL is passed in lpProgress, the message store provider displays a progress indicator using the MAPI progress object implementation. The lpProgress parameter is ignored unless the FOLDER_DIALOG flag is set in ulFlags.
ulFlags
[in] Bitmask of flags that controls how the folder is emptied. The following flags can be set:
DEL_ASSOCIATED
Deletes all subfolders, including subfolders containing messages with associated content. The DEL_ASSOCIATED flag only has meaning for the top-level folder the call acts on.
FOLDER_DIALOG
Displays a progress indicator while the operation proceeds.

Return Values

S_OK
The folder was successfully emptied.
MAPI_W_PARTIAL_COMPLETION
The call succeeded, but the folder was not completely emptied. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IMAPIFolder::EmptyFolder method deletes all of a folder's contents without deleting the folder itself.

During an EmptyFolder call, submitted messages are not deleted.

A folder's associated information includes messages that are used to describe views and form definitions.

Notes to Implementers

Do not call IMsgStore::AbortSubmit for messages in the folder that have been submitted. Submitted messages are not deleted.

Notes to Callers

Expect these return values under the following conditions:

Condition | Return value
EmptyFolder has successfully emptied the folder. | S_OK
EmptyFolder was unable to completely empty the folder. | MAPI_W_PARTIAL_COMPLETION
EmptyFolder was unable to complete. | Any error value

When EmptyFolder is unable to complete, do not assume that no work was done. EmptyFolder might have been able to delete some of the folder's contents before encountering the error.


IMAPIFolder::GetMessageStatus

The IMAPIFolder::GetMessageStatus method obtains the status associated with a message in a particular folder — for example, whether that message is marked for deletion.

Quick Info

See IMAPIFolder : IMAPIContainer.

HRESULT GetMessageStatus(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  ULONG ulFlags,
  ULONG FAR * lpulMessageStatus
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier for the message whose status is obtained.
ulFlags
Reserved; must be zero.
lpulMessageStatus
[out] Pointer to a pointer to a bitmask of flags indicating the message's status. Bits 0 through 15 are reserved and must be zero; bits 16 through 31 are available for implementation-specific use.

The following flags can be set:

MSGSTATUS_DELMARKED
The message has been marked for deletion.
MSGSTATUS_HIDDEN
The message is not to be displayed.
MSGSTATUS_HIGHLIGHTED
The message is to be displayed highlighted.
MSGSTATUS_REMOTE_DELETE
The message has been marked for deletion at the remote message store without downloading to the local client.
MSGSTATUS_REMOTE_DOWNLOAD
The message has been marked for downloading from the remote message store to the local client.
MSGSTATUS_TAGGED
The message has been tagged for a client-defined purpose.

Return Values

S_OK
The message status was successfully retrieved.

Remarks

The IMAPIFolder::GetMessageStatus method returns the status of a message. Message status is stored in the message's PR_MSG_STATUS property.

Notes to Implementers

How the message status bits are set, cleared, and used depends entirely on your implementation, except that bits 0 through 15 are reserved and must be zero. If you store messages in the IPM subtree, MAPI reserves bits 16 through 31 for use by IPM clients. If you store messages in other subtrees, you can use bits 16 through 31 for your own purposes.

See Also

IMAPIFolder::SetMessageStatus


IMAPIFolder::SaveContentsSort

The IMAPIFolder::SaveContentsSort method sets the default sort order for a folder's contents table.

Quick Info

See IMAPIFolder : IMAPIContainer.

HRESULT SaveContentsSort(
  LPSSortOrderSet lpSortCriteria,
  ULONG ulFlags
);

Parameters

lpSortCriteria
[in] Pointer to an SSortOrderSet structure containing the default sort order.
ulFlags
[in] Bitmask of flags that controls how the default sort order is set. The following flag can be set:
RECURSIVE_SORT
The default sort order set applies to the indicated folder and to all of its subfolders.

Return Values

S_OK
The sort order was successfully saved.
MAPI_E_NO_SUPPORT
The message store provider does not support saving a sort order for its folder contents tables.

Remarks

The IMAPIFolder::SaveContentsSort method establishes a default sort order for a folder's contents table. That is, when a client calls the folder's IMAPIContainer::GetContentsTable method after calling SaveContentsSort, the rows in the returned contents table will appear in the order established by SaveContentsSort.

Not all message store providers support SaveContentsSort; it is acceptable for message store providers to return MAPI_E_NO_SUPPORT from the SaveContentsSort method.

See Also

IMAPIContainer::GetContentsTable, SSortOrderSet


IMAPIFolder::SetMessageStatus

The IMAPIFolder::SetMessageStatus method sets the status associated with a message— for example, whether that message is marked for deletion.

Quick Info

See IMAPIFolder : IMAPIContainer.

HRESULT SetMessageStatus(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  ULONG ulNewStatus,
  ULONG ulNewStatusMask,
  ULONG FAR * lpulOldStatus
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier for the message whose status is set.
ulNewStatus
[in] New status to be assigned.
ulNewStatusMask
[in] Bitmask of flags that is applied to the new status indicating the flags to be set.

The following flags can be set:

MSGSTATUS_DELMARKED
The message has been marked for deletion.
MSGSTATUS_HIDDEN
The message is not to be displayed.
MSGSTATUS_HIGHLIGHTED
The message is to be displayed as highlighted.
MSGSTATUS_REMOTE_DELETE
The message has been marked for deletion at the remote message store without downloading to the local client.
MSGSTATUS_REMOTE_DOWNLOAD
The message has been marked for downloading from the remote message store to the local client.
MSGSTATUS_TAGGED
The message has been tagged for a client-defined purpose.
lpulOldStatus
[out] Pointer to the previous status of the message.

Return Values

S_OK
The message status was successfully set.

Remarks

The IMAPIFolder::SetMessageStatus method sets the status associated with a message — the value that is stored in its PR_MSG_STATUS property.

Notes to Implementers

How the message status bits are set, cleared, and used depends entirely on your implementation, except that bits 0 through 15 are reserved and must be zero.

A remote transport provider's implementation of this method must follow the semantics described here. There are no special considerations. Clients use this method to set the MSGSTATUS_REMOTE_DOWNLOAD and MSGSTATUS_REMOTE_DELETE bits to indicate that a particular message is to be downloaded or deleted from the remote message store. A remote transport provider does not have to implement the related GetMessageStatus method. Clients must look in the folder's contents table to determine the status of a message.

Notes to Callers

You can use the PR_MSG_STATUS property of a message to negotiate a message lockout operation with other clients. Designate a bit as the lockout bit. To determine if the lockout bit was set, examine the previous value for message status in the lpulOldStatus parameter. Use the other bits in the ulNewStatus parameter to track message status without interfering with the lockout bit.

See Also

IMAPIFolder::GetMessageStatus


IMAPIFolder::SetReadFlags

The IMAPIFolder::SetReadFlags method sets or clears the MSGFLAG_READ flag in the PR_MESSAGE_FLAGS property of one or more of the folder's messages and manages the sending of read reports.

Quick Info

See IMAPIFolder : IMAPIContainer.

HRESULT SetReadFlags(
  LPENTRYLIST lpMsgList,
  ULONG ulUIParam,
  LPMAPIPROGRESS lpProgress,
  ULONG ulFlags
);

Parameters

lpMsgList
[in] Pointer to an array of ENTRYLIST structures that identify the message or messages with read flags to set or clear. If lpMsgList is set to NULL, the read flags for all of the folder's messages are set or cleared.
ulUIParam
[in] Handle of the parent window for the progress indicator. The ulUIParam parameter is ignored unless the MESSAGE_DIALOG flag is set in the ulFlags parameter.
lpProgress
[in] Pointer to a progress object for displaying a progress indicator. If NULL is passed in lpProgress, the message store provider displays a progress indicator using MAPI's implementation. The lpProgress parameter is ignored unless the MESSAGE_DIALOG flag is set in ulFlags.
ulFlags
[in] Bitmask of flags that controls the setting of a message's read flag and the processing of read reports. The following flags can be set:
CLEAR_READ_FLAG
The MSGFLAG_READ flag should be cleared in PR_MESSAGE_FLAGS and no read report should be sent.
CLEAR_NRN_PENDING
The MSGFLAG_NRN_PENDING flag should be cleared in PR_MESSAGE_FLAGS and a nonread report should not be sent.
CLEAR_RN_PENDING
The MSGFLAG_RN_PENDING flag should be cleared in PR_MESSAGE_FLAGS and no read report should be sent.
GENERATE_RECEIPT_ONLY
A read report should be sent if one is pending, but there should be no change in the state of the MSGFLAG_READ flag.
MAPI_DEFERRED_ERRORS
Allows SetReadFlags to return successfully, possibly before the operation has completed.
MESSAGE_DIALOG
Displays a progress indicator while the operation proceeds.
SUPPRESS_RECEIPT
A pending read report should be canceled if a read report had been requested and this call changes the state of the message from unread to read. If this call does not change the state of the message, the message store provider can ignore this flag.

Return Values

S_OK
The read flag for the specified message or messages was successfully set or cleared.
MAPI_E_NO_SUPPRESS
The message store provider does not support the suppression of read reports.
MAPI_E_INVALID_PARAMETER
One of the following combinations of flags is set in the ulFlags parameter:
  • SUPPRESS_RECEIPT | CLEAR_READ_FLAG
  • SUPPRESS_RECEIPT | CLEAR_READ_FLAG | GENERATE_RECEIPT_ONLY
  • CLEAR_READ_FLAG | GENERATE_RECEIPT_ONLY
MAPI_W_PARTIAL_COMPLETION
The call succeeded, but not all of the messages were successfully processed. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IMAPIFolder::SetReadFlags method sets or clears the MSGFLAG_READ flag in the PR_MESSAGE_FLAGS property of one or more of the folder's messages. Setting the MSGFLAG_READ flag marks a message as having been read, which does not necessarily indicate that the intended recipient has actually read the message.

SetReadFlags also manages the sending of read reports.

The read flag cannot be altered for:

  • Messages that do not exist.
  • Messages that have been moved elsewhere.
  • Messages that are open with read/write access.
  • Messages that are currently submitted.

Notes to Implementers

You can choose not to support the sending of read reports and the request to suppress read reports. To avoid suppressing a read report, return MAPI_E_NO_SUPPRESS when SetReadFlags is called with SUPPRESS_RECEIPT set in ulFlags.

When lpMsgList points to more than one message, perform the operation as completely as possible for each message. Do not stop the operation prematurely unless a failure occurs that is beyond your control, such as running out of memory, running out of disk space, or corruption in the message store.

If none of the flags is set in the ulFlags parameter, the following rules apply:

  • If MSGFLAG_READ is already set, do nothing.
  • If MSGFLAG_READ is not set, set it immediately and send any pending read reports if the PR_READ_RECEIPT_REQUESTED property is set.

When the SUPPRESS_RECEIPT flag is set:

  • If MSGFLAG_READ is already set, do nothing.
  • If MSGFLAG_READ is not set, set it and cancel any pending read reports.

When the CLEAR_READ_FLAG flag is set, clear the MSGFLAG_READ flag in each message's PR_MESSAGE_FLAGS property and do not send any read reports.

When the GENERATE_RECEIPT_ONLY flag is set, send any pending read reports. Do not set or clear MSGFLAG_READ.

When both the SUPPRESS_RECEIPT and GENERATE_RECEIPT_ONLY flags are set, set PR_READ_RECEIPT_REQUESTED to FALSE if it is set and do not send a read report.

Notes to Callers

Expect these return values under the following conditions:

Condition | Return value
SetReadFlags has successfully processed every message. | S_OK
SetReadFlags was unable to successfully process every message. | MAPI_W_PARTIAL_COMPLETION or MAPI_E_NOT_FOUND
SetReadFlags was unable to complete. | Any error value except MAPI_E_NOT_FOUND

When SetReadFlags is unable to complete, do not assume that no work was done. SetReadFlags might have been able to set or clear the MSGFLAG_READ flag for one or more of the messages before encountering the error.

See Also

IMessage::SetReadFlag, PR_MESSAGE_FLAGS


IMAPIForm : IUnknown

The IMAPIForm interface is used by form viewers to work with form view contexts and form notification, to perform form verbs, and to shut down forms.

Quick Info

Header file: | MAPIFORM.H
Exposed by: | Form objects
Implemented by: | Form servers
Called by: | Form viewers
Interface identifier: | IID_IMAPIForm
Pointer type: | LPMAPIFORM

Vtable Order

SetViewContext | Establishes a view context for the form.
GetViewContext | Returns the current view context for the form.
ShutdownForm | Closes the form.
DoVerb | Requests that the form perform whatever tasks it associates with a specific verb.
Advise | Registers a form viewer for notifications about events affecting the form.
Unadvise | Cancels a registration for notifications with a form viewer previously established with a call to the IMAPIForm::Advise method.


IMAPIForm::Advise

The IMAPIForm::Advise method registers a form viewer for notifications about events affecting the form.

Quick Info

See IMAPIForm : IUnknown.

HRESULT Advise(
  LPMAPIVIEWADVISESINK pAdvise,
  ULONG FAR * pulConnection
);

Parameters

pAdvise
[in] Pointer to a view advise sink object to receive the subsequent notifications.
pulConnection
[out] Pointer to a nonzero value that represents the successful notification registration.

Return Values

S_OK
The registration was successful.
E_OUTOFMEMORY
The registration was unsuccessful because of insufficient memory.

Remarks

Form viewers call a form's IMAPIForm::Advise method to register for notification when changes occur to the form.

Notes to Implementers

Keep a copy of the view advise sink pointer passed in the pAdvise parameter so that you can use it to call the appropriate IMAPIViewAdviseSink method when an event occurs. Call the view advise sink's IUnknown::AddRef method to retain the pointer until notification registration is canceled. Set the contents of the pulConnection parameter to a nonzero number.

Many forms implement a helper object to handle the registration and subsequent notification of events.

For more information on the notification process in general, see Event Notification in MAPI.

For more information about notification and forms, see Sending and Receiving Form Notifications.

See Also

IMAPIForm::Unadvise, IMAPIViewAdviseSink : IUnknown


IMAPIForm::DoVerb

The IMAPIForm::DoVerb method requests that the form perform whatever tasks it associates with a specific verb.

Quick Info

See IMAPIForm : IUnknown.

HRESULT DoVerb(
  LONG iVerb,
  LPMAPIVIEWCONTEXT lpViewContext,
  ULONG hwndParent,
  LPCRECT lprcPosRect
);

Parameters

iVerb
[in] Number associated with one of the form's verbs.
lpViewContext
[in] Pointer to a view context object. The lpViewContext parameter can be NULL.
hwndParent
[in] Handle of the parent window for any dialog boxes or windows this method displays. The hwndParent parameter should be NULL if the dialog box or window is not modal.
lprcPosRect
[in] Pointer to a Win32 RECT structure containing the form's window size and position.

Return Values

S_OK
The verb was successfully invoked.
OLEOBJ_S_CANNOT_DOVERB_NOW
The verb represented by the iVerb parameter is valid, but the form cannot perform the operations associated with it at the present time.

Remarks

Form viewers call the IMAPIForm::DoVerb method to request that the form perform the tasks that it associates with each of the verbs that the form supports.

Each of the supported verbs is identified by a numeric value, passed to DoVerb in the iVerb parameter. Typical implementations of DoVerb contain a switch statement that tests the values that are valid for the iVerb parameter for the form.

Notes to Implementers

If the form viewer specifies a view context in the lpViewContext parameter, use it in your DoVerb implementation rather than the view context passed in an earlier call to the IMAPIForm::SetViewContext method. Make whatever changes that are necessary to your internal data structures and do not save the view context.

Perform the following tasks in your DoVerb implementation:

  • Execute whatever code is necessary for the particular verb associated with the iVerb parameter.
  • If necessary, restore the original view context.
  • If an unknown verb number was passed in, return MAPI_E_NO_SUPPORT. Otherwise, return a result based on the success or failure of whatever verb was executed.
  • Shut the form down. It is always your responsibility to shut down after completing a DoVerb call.

Some verbs, such as Print, should be modal with respect to the DoVerb call — that is, the indicated operation must be finished before the DoVerb call returns.

To obtain the RECT structure used by a form's window, call the Win32 function GetWindowRect.

Do not save the handle in the hwndParent parameter because although it usually remains valid until the completion of DoVerb, it can be destroyed immediately upon the call's return.

Notes to Callers

You can make nonmodal verbs act as modal verbs by pointing lpViewContext to a view context implementation that returns the VCSTATUS_MODAL flag from its GetViewStatus method.

For more information about verbs in MAPI, see Form Verbs. For more information about how verbs are handled in OLE, see the OLE Programmer's Reference.

See Also

IMAPIForm::SetViewContext, IMAPIViewContext::GetViewStatus


IMAPIForm::GetViewContext

The IMAPIForm::GetViewContext method returns the current view context for the form.

Quick Info

See IMAPIForm : IUnknown.

HRESULT GetViewContext(
  LPMAPIVIEWCONTEXT FAR * ppViewContext
);

Parameters

ppViewContext
[out] Pointer to a pointer to the form's view context.

Return Values

S_OK
The form's current view context was successfully returned.
S_FALSE
There is no view context for the form.

Remarks

Form viewers call GetViewContext to obtain a pointer to the view context established in a previous call to IMAPIForm::SetViewContext. If no prior call has been made to SetViewContext, GetViewContext sets ppViewContext to NULL.

Notes to Implementers

Copy your form's view context pointer into the pointer passed in by the calling form viewer in the ppViewContext parameter. If your form does not have a view context, set ppViewContext to NULL.

See Also

IMAPIViewContext : IUnknown


IMAPIForm::SetViewContext

The IMAPIForm::SetViewContext method establishes a view context for the form.

Quick Info

See IMAPIForm : IUnknown.

HRESULT SetViewContext(
  LPMAPIVIEWCONTEXT pViewContext
);

Parameters

pViewContext
[in] Pointer to the new view context for the form.

Return Values

S_OK
The view context was successfully set.

Remarks

Form viewers call the IMAPIForm::SetViewContext method to establish a particular form view context as current. A form can have only one view context at a time.

Notes to Implementers

Most form servers implement SetViewContext using this algorithm:

  • If a view context already exists for the form, cancel the form's registration by calling the IMAPIViewContext::SetAdviseSink method with NULL in the pmnvs parameter, and then call the view context's Release method to decrement its reference count.
  • If the new view context is not NULL, call IMAPIViewContext::SetAdviseSink using the pViewContext parameter to set up a new view advise sink.
  • If the new view context is not NULL, call the IMAPIViewContext::GetViewStatus method to determine which status flags have been set.
  • If the new view context is not NULL, store it and call its AddRef method to increment its reference count.
  • Update any user interface elements that depend on the view context.

Depending on the status flags returned from GetViewStatus, SetViewContext can also perform other actions. For example, if the VCSTATUS_NEXT and VCSTATUS_PREV flags are returned, SetViewContext can enable the Next and Previous buttons for the new view context.


IMAPIForm::ShutdownForm

The IMAPIForm::ShutdownForm method closes the form.

Quick Info

See IMAPIForm : IUnknown.

HRESULT Close(
  ULONG ulSaveOptions
);

Parameters

ulSaveOptions
[in] Value that controls how or whether data in the form is saved before the form is closed. One of the following values can be set:
SAVEOPTS_NOSAVE
Form data should not be saved.
SAVEOPTS_PROMPTSAVE
The user should be prompted to save any changed data in the form.
SAVEOPTS_SAVEIFDIRTY
Form data should be saved if it has changed since the last save. If no user interface is being displayed, the form can optionally switch to using the functionality for the SAVEOPTS_NOSAVE option.

Return Values

S_OK
The form was closed.
E_UNEXPECTED
The form was already closed by a prior call to ShutdownForm.

Remarks

Form viewers call the IMAPIForm::ShutdownForm method to close a form.

Notes to Implementers

Perform the following tasks in your implementation of ShutdownForm:

  1. Check that a viewer has not already called ShutdownForm and return E_UNEXPECTED if it has. Although this is unlikely, it is wise to make the check.
  2. Call your form's IUnknown::AddRef method so that storage for your form and any internal data structures remain available until processing is finished.
  3. Determine whether or not there are any unsaved changes to the form's data. Save unsaved data according to how the ulSaveOptions parameter is set by calling your viewer's SaveMessage method.
  4. Destroy your form's user interface window.
  5. Release your form's message and message site objects by calling their IUnknown::Release methods.
  6. Notify all registered viewers of the pending shutdown by calling their IMAPIViewAdviseSink::OnShutdown methods.
  7. Call IMAPIViewContext::SetAdviseSink to cancel your form's registration for notification by setting the advise sink pointer to NULL.
  8. Call the MAPIFreeBuffer function to free the memory for your form's properties.
  9. Call your form's IUnknown::Release method, matching the AddRef call made in step 2.
  10. Return S_OK.

Note After these actions have been completed, the only valid methods on the form object that may be called are those from the IUnknown interface.

Notes to Callers

When ShutdownForm returns, regardless of whether it returns an error, release the form by calling its IUnknown::Release method. You can safely ignore any errors returned by ShutdownForm.

See Also

IMAPIViewAdviseSink::OnShutdown


IMAPIForm::Unadvise

The IMAPIForm::Unadvise method cancels a registration for notifications with a form viewer previously established with a call to the IMAPIForm::Advise method.

Quick Info

See IMAPIForm : IUnknown.

HRESULT Unadvise(
  ULONG ulConnection
);

Parameters

ulConnection
[in] Connection number identifying the notification registration to be canceled.

Return Values

S_OK
The registration was canceled.
E_INVALIDARG
The connection number passed in the ulConnection parameter does not represent a valid registration.

Remarks

Form viewers call the IMAPIForm::Unadvise method to cancel a registration for notification that they initially established by calling IMAPIForm::Advise.

Notes to Implementers

Discard the pointer that you are holding to the form viewer's view advise sink by calling its IUnknown::Release method. Generally, Release is called during the Unadvise call, but if another thread is in the process of calling one of the IMAPIViewAdviseSink methods for the view advise sink, delay the Release call until the IMAPIViewAdviseSink method returns.

See Also

IMAPIForm::Advise, IMAPIViewAdviseSink : IUnknown


IMAPIFormAdviseSink : IUnknown

The IMAPIFormAdviseSink interface is implemented by form servers to receive notifications from form viewers.

Quick Info

Header file: | MAPIFORM.H
Exposed by: | Form advise sink objects
Implemented by: | Form servers
Called by: | Form viewers
Interface identifier: | IID_IMAPIFormAdviseSink
Pointer type: | LPMAPIFORMADVISESINK

Vtable Order

OnChange | Indicates that a change has occurred in the status of the form viewer.
OnActivateNext | Indicates whether of not the form can handle the message class of the next message to display.

Remarks

Form servers use a form advise sink object to implement IMAPIFormAdviseSink rather than including it with their form object. Therefore, form viewers should expect a call to a form's QueryInterface method to obtain a pointer to this interface to fail.

Form servers call a viewer's IMAPIViewContext::SetAdviseSink method to register for notifications. A pointer to their IMAPIFormAdviseSink implementation is included as a parameter.


IMAPIFormAdviseSink::OnActivateNext

The IMAPIFormAdviseSink::OnActivateNext method indicates whether or not the form can handle the message class of the next message to display.

Quick Info

See IMAPIFormAdviseSink : IUnknown.

HRESULT OnActivateNext(
  LPCSTR lpszMessageClass,
  ULONG ulMessageStatus,
  ULONG ulMessageFlags,
  LPPERSISTMESSAGE FAR * ppPersistMessage
);

Parameters

lpszMessageClass
[in] Pointer to the message class of the next message.
ulMessageStatus
[in] Bitmask of client-defined or provider-defined flags — copied from the PR_MSG_STATUS property of the next message to display — that provides status information relating to the contents table in which it is included.
ulMessageFlags
[in] Pointer to a bitmask of flags — copied from the PR_MESSAGE_FLAGS property of the next message to display — that indicates the current state of the message.
ppPersistMessage
[out] Pointer to a pointer to the IPersistMessage implementation for the form object used for the new form, if a new form is required. A pointer to NULL can be returned if the current form object can be used to display and save the next message.

Return Values

S_OK
The notification was successful and the form can handle the next message.
S_FALSE
The form does not handle the message class of the next message.

Remarks

Form viewers call the IMAPIFormAdviseSink::OnActivateNext method to help the form determine whether it is capable of displaying the next message in a folder. The next message could be a message of any class, but typically it is of the same class or a related class. This makes the process of reading multiple messages of the same class more efficient by allowing client applications to reuse form objects whenever possible.

Most form objects will use the message class pointed to by lpszMessageClass to determine whether or not they can handle the next message. Usually a form can handle messages that belong to classes of which the form's default class is a subclass as well as messages that belong to the default class. However, a form can use other factors to determine without question whether or not a message can be handled, such as the sent or unsent status of the next message.

Notes to Implementers

Return S_OK and NULL in the ppPersistMessage parameter if your form can handle the message class. If your form can create a new form that can handle the message that your form is unable to handle, perform the following tasks:

  1. Call your form's class factory to create an instance of a new form object.
  2. Store that instance in the contents of the ppPersistMessage pointer parameter.
  3. Return S_OK.

The message will be loaded by the form viewer using the IPersistMessage::Load method belonging to the object pointed to by ppPersistMessage.

If neither your form nor a form that you can create can handle the next message, return S_FALSE. MAPI discourages forms from returning this value because it results in degraded performance in the form viewer.

See Also

IPersistMessage::Load


IMAPIFormAdviseSink::OnChange

The IMAPIFormAdviseSink::OnChange method indicates that a change has occurred in the status of the form viewer.

Quick Info

See IMAPIFormAdviseSink : IUnknown.

HRESULT OnChange(
  ULONG ulDir
);

Parameters

ulDir
[in] Bitmask of flags that provides information about the change that has occurred in the viewer and the expected response in the form. The following flags can be set:
VCSTATUS_CATEGORY
There is a next or previous message in another category.
VCSTATUS_INTERACTIVE
The form should display a user interface. If this flag is not set, the form should suppress displaying a user interface even in response to a verb that usually causes a user interface to be displayed.
VCSTATUS_MODAL
The form is to be modal to the form viewer.
VCSTATUS_NEXT
There is a next message in the form viewer.
VCSTATUS_PREV
There is a previous message in the form viewer.
VCSTATUS_READONLY
Delete, submit, and move operations should be disabled.
VCSTATUS_UNREAD
There is a next or previous unread message in the form viewer.

Return Values

S_OK
The notification was successful.

Remarks

Form viewers call the IMAPIFormAdviseSink::OnChange method to notify the form about a change in a viewer's status. Usually, the only change is setting or clearing the VCSTATUS_NEXT or VCSTATUS_PREVIOUS flag based on the presence or absence of a next or previous message in the viewer. The form object then enables or disables any next or previous actions it supports accordingly.

The settings of VCSTATUS_MODAL and VCSTATUS_INTERACTIVE cannot change in a view context once it has been created.

Notes to Implementers

The specific implementation of this method is entirely dependent on the specifics of your form. Most form objects use this method to alter their user interface — for example, enable or disable menu commands or buttons — to match the viewer status flags parameter.

See Also

IMAPIViewContext::ActivateNext


IMAPIFormContainer : IUnknown

The IMAPIFormContainer interface manages forms within form libraries. This interface is used to create application-specific form libraries.

Quick Info

Header file: | MAPIFORM.H
Exposed by: | Form container objects
Implemented by: | Form library providers
Called by: | Client applications
Interface identifier: | IID_IMAPIFormContainer
Pointer type: | LPMAPIFORMCONTAINER

Vtable Order

InstallForm | Installs a form into a form container.
RemoveForm | Removes a particular form from a form container.
ResolveMessageClass | Resolves a message class to its form within a form container and returns a form information object for that form.
ResolveMultipleMessageClasses | Resolves a group of message classes to their forms within a form container and returns an array of form information objects for those forms.
CalcFormPropSet | Returns an array of the properties used by all forms installed within a form container.
GetDisplay | Returns the display name of a form container.


IMAPIFormContainer::CalcFormPropSet

The IMAPIFormContainer::CalcFormPropSet method returns an array of the properties used by all forms installed within a form container.

Quick Info

See IMAPIFormContainer : IUnknown.

HRESULT CalcFormPropSet(
  ULONG ulFlags,
  LPMAPIFORMPROPARRAY FAR * ppResults
);

Parameters

ulFlags
[in] Bitmask of flags that controls how the property array in the ppResults parameter is returned. The following flags can be set:
FORMPROPSET_INTERSECTION
The returned array contains the intersection of the forms' properties.
FORMPROPSET_UNION
The returned array contains the union of the forms' properties.
MAPI_UNICODE
The strings returned in the array are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
ppResults
[out] Pointer to a pointer to the returned SMAPIFormPropArray structure. This structure contains all properties used by the installed forms.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Remarks

Client applications call the IMAPIFormContainer::CalcFormPropSet method to obtain an array of properties used by all forms installed within a form container. CalcFormPropSet works like the IMAPIFormMgr::CalcFormPropSet method, except that it operates on every form registered in a particular container.

Notes to Implementers

Form library providers that do not support Unicode strings should return MAPI_E_BAD_CHARWIDTH if MAPI_UNICODE is passed.

Notes to Callers

CalcFormPropSet either takes an intersection or a union of the forms' property sets, depending on the flag set in the ulFlags parameter, and it returns an SMAPIFormPropArray structure containing the resulting group of properties.

If a client passes the MAPI_UNICODE flag in ulFlags, all strings returned are Unicode.

See Also

IMAPIFormMgr::CalcFormPropSet, SMAPIFormPropArray


IMAPIFormContainer::GetDisplay

The IMAPIFormContainer::GetDisplay method returns the display name of a form container.

Quick Info

See IMAPIFormContainer : IUnknown.

HRESULT GetDisplay(
  ULONG ulFlags,
  LPTSTR FAR * pszDisplayName
);

Parameters

ulFlags
[in] Bitmask of flags that controls the type of the returned string. The following flag can be set:
MAPI_UNICODE
The returned string is in Unicode format. If the MAPI_UNICODE flag is not set, the string is in ANSI format.
pszDisplayName
[out] Pointer to a string containing the display name of the form container.

Return Values

S_OK
The call succeeded and has returned the expected value or values.


IMAPIFormContainer::InstallForm

The IMAPIFormContainer::InstallForm method installs a form into a form library.

Quick Info

See IMAPIFormContainer : IUnknown.

HRESULT InstallForm(
  ULONG ulUIParam,
  ULONG ulFlags,
  LPCTSTR szCfgPathName
);

Parameters

ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays. The ulUIParam parameter is ignored unless the client application sets the MAPI_DIALOG flag in the ulFlags parameter. The ulUIParam parameter can be NULL if MAPI_DIALOG is not also passed.
ulFlags
[in] Bitmask of flags that controls the installation of the form. The following flags can be set:
MAPI_DIALOG
Displays a dialog box to provide progress information or prompt the user for additional information. If this flag is not set, no dialog box is displayed.
MAPI_UNICODE
The passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
MAPIFORM_INSTALL_OVERWRITEONCONFLICT
If another form already exists that handles the message class handled by this form, then replace the existing form with this one. This flag is ignored if the MAPI_DIALOG flag is also present.
szCfgPathName
[in] Path to the form's configuration file.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_EXTENDED_ERROR
An implementation error occurred; to get the MAPIERROR structure associated with the error, call the IMAPIFormContainer::GetLastError method.
MAPI_E_USER_CANCEL
The user canceled the installation of the form, typically by clicking the Cancel button in a dialog box.

Notes to Implementers

Form library providers should fill in a MAPIERROR structure and return MAPI_E_EXTENDED_ERROR if any of the following conditions occur:

  • The configuration file is not found.
  • The configuration file is not readable.
  • The configuration file is invalid.

Notes to Callers

Client applications call the IMAPIFormContainer::InstallForm method to install a form into a specific form container. The szCfgPathName parameter must contain the path of a form configuration file — that is, a file with the .CFG extension — that describes the form and its implementation. The flags in the ulFlags parameter specify:

  • That a user interface enabling the user installing the form to specify details of installation is displayed, if the MAPI_DIALOG flag is set.
  • That any previous form for the same message class is replaced with the form being installed, if the MAPIFORM_INSTALL_OVERWRITEONCONFLICT flag is set. Otherwise, the form installation is merged with the current form description, if one exists.
  • That MAPIFORM_INSTALL_OVERWRITEONCONFLICT is ignored when MAPI_DIALOG is present.
  • That the absence of MAPIFORM_INSTALL_OVERWRITEONCONFLICT in the flag set means that a merge will be done. Any new platforms in the .CFG file not currently present in the form description will be installed and no other changes will take place.
  • That the path to the form configuration file is a Unicode string, if the MAPI_UNICODE flag is set.

Clients should call IMAPIFormContainer::GetLastError if InstallForm returns MAPI_E_EXTENDED_ERROR and should check the returned MAPIERROR structure to determine the condition causing the error.


IMAPIFormContainer::RemoveForm

The IMAPIFormContainer::RemoveForm method removes a particular form from a form container.

Quick Info

See IMAPIFormContainer : IUnknown.

HRESULT RemoveForm(
  LPCSTR szMessageClass
);

Parameters

szMessageClass
[in] String naming the message class of the form to be removed from the form container. Message class names are always ANSI strings, never Unicode.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_NOT_FOUND
The message class passed in the szMessageClass parameter does not match the message class of any form in the form container.


IMAPIFormContainer::ResolveMessageClass

The IMAPIFormContainer::ResolveMessageClass method resolves a message class to its form within a form container and returns a form information object for that form.

Quick Info

See IMAPIFormContainer : IUnknown.

HRESULT ResolveMessageClass(
  LPCSTR szMessageClass,
  ULONG ulFlags,
  LPMAPIFORMINFO FAR * ppforminfo
);

Parameters

szMessageClass
[in] String naming the message class being resolved. Message class names are always ANSI strings, never Unicode.
ulFlags
[in] Bitmask of flags that controls how the message class is resolved. The following flag can be set:
MAPIFORM_EXACTMATCH
Only message class strings that are an exact match should be resolved.
ppforminfo
[out] Pointer to a pointer to the returned form information object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_NOT_FOUND
The message class passed in the szMessageClass parameter does not match the message class for any form in the form container.

Remarks

Client applications call the IMAPIFormContainer::ResolveMessageClass method to resolve a message class to a form within a form container. The form information object returned in the ppforminfo parameter provides further access to the properties of the form with the given message class.

Notes to Callers

To resolve a message class to a form, pass in the name of the message class to be resolved, for example IPM.HelpDesk.Software. To force the resolution to be exact — that is, to prevent resolution to a superclass of the message class — the MAPIFORM_EXACTMATCH flag can be passed in the ulFlags parameter.

The class identifier for the resolved message class is returned as part of the form information object. Do not assume that the class identifier exists in the OLE library until after calling either the IMAPIFormMgr::PrepareForm method or the IMAPIFormMgr::CreateForm method.

See Also

IMAPIFormInfo : IMAPIProp, IMAPIFormMgr::CreateForm, IMAPIFormMgr::PrepareForm


IMAPIFormContainer::ResolveMultipleMessageClasses

The IMAPIFormContainer::ResolveMultipleMessageClasses method resolves a group of message classes to their forms within a form container and returns an array of form information objects for those forms.

Quick Info

See IMAPIFormContainer : IUnknown.

HRESULT ResolveMultipleMessageClasses (
  LPSMESSAGECLASSARRAY pMsgClassArray,
  ULONG ulFlags,
  LPSMAPIFORMINFOARRAY FAR * ppfrminfoarray
);

Parameters

pMsgClassArray
[in] Pointer to an array containing the names of the message classes to resolve. Message class names are always ANSI strings, never Unicode.
ulFlags
[in] Bitmask of flags that controls how the message classes are resolved. The following flag can be set:
MAPIFORM_EXACTMATCH
Only message class strings that are an exact match should be resolved.
ppfrminfoarray
[out] Pointer to a pointer to an array of form information objects. If a client application passes NULL in the pMsgClassArray parameter, the ppfrminfoarray parameter contains form information objects for all forms in the container.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Client applications call the IMAPIFormContainer::ResolveMultipleMessageClasses method to resolve a group of message classes to forms within a form container. The array of form information objects returned in the ppfrminfoarray parameter provides further access to each of the forms' properties.

Notes to Callers

To resolve a group of message classes to forms, pass in an array of message class names to be resolved. To force the resolution to be exact — that is, to prevent resolution to a superclass of the message class — the MAPIFORM_EXACTMATCH flag can be passed in the ulFlags parameter.

If a message class cannot be resolved to a form, NULL is returned for that message class in the form information array. Therefore, even if the method returns S_OK, do not assume that all message classes have been successfully resolved. Instead, check the values in the returned array.

See Also

IMAPIFormContainer::ResolveMessageClass


IMAPIFormFactory : IUnknown

The IMAPIFormFactory interface supports the use of configurable run-time forms in distributed computing environments.

Quick Info

Header file: | MAPIFORM.H
Exposed by: | Form factory objects
Implemented by: | Form servers
Called by: | Form viewers
Interface identifier: | IID_IMAPIFormFactory
Pointer type: | LPMAPIFORMFACTORY

Vtable Order

CreateClassFactory | Returns a class factory object for the form.
LockServer | Keeps an open form server in memory.

Remarks

The IMAPIFormFactory interface is based on the OLE IClassFactory interface, and objects implementing IMAPIFormFactory should also inherit from IClassFactory. For more information on IClassFactory, see the OLE Programmer's Reference.

IMAPIFormFactory is the interface that form viewers use to create new form objects when a form server supports more than one message class — that is, more than one type of form object.


IMAPIFormFactory::CreateClassFactory

The IMAPIFormFactory::CreateClassFactory method returns a class factory object for the form.

Quick Info

See IMAPIFormFactory : IUnknown.

HRESULT CreateClassFactory(
  REFCLSID clsidForm,
  ULONG ulFlags,
  LPCLASSFACTORY FAR * lppClassFactory
);

Parameters

clsidForm
[in] Class identifier for the form to be created by the class factory.
ulFlags
Reserved; must be zero.
lppClassFactory
[out] Pointer to the class factory object.

Return Values

S_OK
The class factory object was returned.

Remarks

Form viewers call the IMAPIFormFactory::CreateClassFactory method to obtain a class factory for a specific form. The class factory is used to create instances of a form that handles messages of a specific class and to control the access to these instances.

The CreateClassFactory method is called by form viewers to obtain a class factory object for form servers that implement multiple message classes. This method receives a class identifier (CLSID) as a parameter. Based on that parameter, this method can determine the specific kind of class factory object to return.

Notes to Implementers

You can return from your CreateClassFactory implementation the same class factory object on multiple calls for the same class identifier. Creating a new class factory instance is not required.

You can have a single class factory implementation that creates appropriate class factory instances on demand, or multiple class factory implementations, one for each message class.


IMAPIFormFactory::LockServer

The IMAPIFormFactory::LockServer method keeps an open form server in memory.

Quick Info

See IMAPIFormFactory : IUnknown.

HRESULT LockServer(
  ULONG ulFlags,
  ULONG fLockServer
);

Parameters

ulFlags
Reserved; must be zero.
fLockServer
[in] Variable set to TRUE if the lock count is to be incremented, and FALSE otherwise.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Form viewers call the IMAPIFormFactory::LockServer method to keep an open form server application in memory. Keeping the form server in memory improves its performance when forms are created and released frequently.

Notes to Implementers

The LockServer method is very similar to the IClassFactory::LockServer method. Essentially, this method maintains a count of how many times it has been called and as long as that count is greater than 0, prevents the form server from being unloaded from memory. You can use the OLE function CoLockObjectExternal to implement this. See the OLE Programmer's Reference for details.


IMAPIFormInfo : IMAPIProp

The IMAPIFormInfo interface gives client applications access to useful properties particular to form definition. By keeping form information in a separate object, the form library provider can describe a form to a client without activating the form.

Quick Info

Header file: | MAPIFORM.H
Exposed by: | Form information objects
Implemented by: | Form library providers
Called by: | Client applications
Interface identifier: | IID_IMAPIFormInfo
Pointer type: | LPMAPIFORMINFO
Transaction model: | Nontransacted

Vtable Order

CalcFormPropSet | Returns a pointer to the complete set of properties used by a form.
CalcVerbSet | Returns a pointer to the complete set of verbs used by a form.
MakeIconFromBinary | Builds an icon from an icon property of a form.
SaveForm | Saves a description of a particular form in a configuration file.
OpenFormContainer | Returns a pointer to the form container in which a particular form is installed.

Remarks

Unlike most interfaces defined in the MAPIFORM.H header file, IMAPIFormInfo inherits from the IMAPIProp interface, as it exports most form information through calls to the IMAPIProp::GetProps method.


IMAPIFormInfo::CalcFormPropSet

The IMAPIFormInfo::CalcFormPropSet method returns a pointer to the complete set of properties used by a form.

Quick Info

See IMAPIFormInfo : IMAPIProp.

HRESULT CalcFormPropSet (
  ULONG ulFlags,
  LPMAPIFORMPROPARRAY FAR * ppFormPropArray
);

Parameters

ulFlags
[in] Bitmask of flags that controls the type of the returned strings. The following flag can be set:
MAPI_UNICODE
The returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
ppFormPropArray
[out] Pointer to a pointer to the returned SMAPIFormPropArray structure.

Return Values

S_OK
The call succeeded and has returned the expected value or values.


IMAPIFormInfo::CalcVerbSet

The IMAPIFormInfo::CalcVerbSet method returns a pointer to the complete set of verbs used by a form.

Quick Info

See IMAPIFormInfo : IMAPIProp.

HRESULT CalcVerbSet(
  ULONG ulFlags,
  LPMAPIVERBARRAY FAR * ppMAPIVerbArray
);

Parameters

ulFlags
[in] Bitmask of flags that controls the type of the returned strings. The following flag can be set:
MAPI_UNICODE
The returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
ppMAPIVerbArray
[out] Pointer to a pointer to the returned SMAPIVerbArray structure containing the form's verbs.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Client applications call the IMAPIFormInfo::CalcVerbSet method to obtain a pointer to the set of verbs used by a form. Within the SMAPIVerbArray structure returned in the ppMAPIVerbArray parameter, the verbs are returned in order of index number; each verb's index is found in its lVerb member. Client applications can use the verb array to dynamically build menus, hide or show buttons, and so on.

See Also

SMAPIVerbArray


IMAPIFormInfo::MakeIconFromBinary

The IMAPIFormInfo::MakeIconFromBinary method builds an icon from an icon property of a form.

Quick Info

See IMAPIFormInfo : IMAPIProp.

HRESULT MakeIconFromBinary(
  ULONG nPropID,
  HICON FAR * phicon
);

Parameters

nPropID
[in] Property identifier for an icon property.
phicon
[out] Pointer to the returned icon.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Client applications call the IMAPIFormInfo::MakeIconFromBinary method to build an icon from an icon property of a form. In the nPropID parameter, MakeIconFromBinary takes the property identifier of one of the icon properties of a form. Using this property identifier, it builds an icon that can be displayed in table views that include property columns for icons.


IMAPIFormInfo::OpenFormContainer

The IMAPIFormInfo::OpenFormContainer method returns a pointer to the form container in which a particular form is installed.

Quick Info

See IMAPIFormInfo : IMAPIProp.

HRESULT OpenFormContainer (
  LPMAPIFORMCONTAINER FAR * ppformcontainer
);

Parameters

ppformcontainer
[out] Pointer to a pointer to the returned form container object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.


IMAPIFormInfo::SaveForm

The IMAPIFormInfo::SaveForm method saves a description of a particular form in a configuration file.

Quick Info

See IMAPIFormInfo : IMAPIProp.

HRESULT SaveForm(
  LPCTSTR szFileName
);

Parameters

szFileName
[in] String naming the form's description message file where its description is saved. This filename must have the .FDM extension.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_EXTENDED_ERROR
The configuration file could not be written. To get the MAPIERROR structure associated with the error, call the IMAPIProp::GetLastError method.
MAPI_E_NO_SUPPORT
SaveForm was probably called to save a form in the local form container. SaveForm is not supported on the local form container.

Remarks

Client applications call the IMAPIFormInfo::SaveForm method to save a description of the current form in the file with the given filename. SaveForm creates a configuration file.

Notes to Callers

Forms can be reinstalled by being selected from a list of form descriptor messages in a dialog box displayed by form library providers. The recommended extension for form descriptor messages is .FDM.

Call IMAPIProp::GetLastError if SaveForm returns MAPI_E_EXTENDED_ERROR, and check the returned MAPIERROR structure to determine the condition causing the error.


IMAPIFormMgr : IUnknown

The IMAPIFormMgr interface is used by form viewers to get information about and activate form servers.

Quick Info

Header file: | MAPIFORM.H
Exposed by: | Form manager objects
Implemented by: | Form library providers
Called by: | Form viewers
Interface identifier: | IID_IMAPIFormMgr
Pointer type: | LPMAPIFORMMGR

Vtable Order

LoadForm | Launches a form to open an existing message.
ResolveMessageClass | Resolves a message class to its form within a form container and returns a form information object for that form.
ResolveMultipleMessageClasses | Resolves a group of message classes to their forms within a form container and returns an array of form information objects for those forms.
CalcFormPropSet | Returns an array of the properties used by a group of forms.
CreateForm | Launches a form to create a new message based on the form's message class.
SelectForm | Presents a dialog box that enables the user to select a form and returns a form information object describing that form.
SelectMultipleForms | Presents a dialog box that enables the user to select multiple forms and returns an array of form information objects describing those forms.
SelectFormContainer | Presents a dialog box that enables the user to select a form container and returns an interface for the container object the user selected.
OpenFormContainer | Opens an IMAPIFormContainer interface for a specific form container.
PrepareForm | Downloads a form for launching.
IsInConflict | Determines whether a form can handle its own message conflicts.


IMAPIFormMgr::CalcFormPropSet

The IMAPIFormMgr::CalcFormPropSet method returns an array of the properties used by a group of forms.

Quick Info

See IMAPIFormMgr : IUnknown.

HRESULT CalcFormPropSet (
  LPSMAPIFORMINFOARRAY pfrminfoarray,
  ULONG ulFlags,
  LPMAPIFORMPROPARRAY FAR * ppResults
);

Parameters

pfrminfoarray
[in] Pointer to an array of form information objects identifying the forms for which to return properties.
ulFlags
[in] Bitmask of flags that controls how the property array in the ppResults parameter is returned. The following flags can be set:
FORMPROPSET_INTERSECTION
The returned array contains the intersection of the form's properties.
FORMPROPSET_UNION
The returned array contains the union of the form's properties.
MAPI_UNICODE
The strings returned in the array are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
ppResults
[out] Pointer to a pointer to the returned SMAPIFormPropArray structure which contains the properties used by the forms.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Remarks

Form viewers call the IMAPIFormContainer::CalcFormPropSet method to obtain an array of the properties used by a group of forms. CalcFormPropSet either takes an intersection or a union of these forms' property sets, depending on the flag set in the ulFlags parameter, and it returns an SMAPIFormPropArray structure containing the resulting group of properties.

Notes to Implementers

If a form viewer passes the MAPI_UNICODE flag in the ulFlags parameter, all strings should be returned as Unicode strings. Form library providers that do not support Unicode strings should return MAPI_E_BAD_CHARWIDTH if MAPI_UNICODE is passed.

See Also

SMAPIFormPropArray


IMAPIFormMgr::CreateForm

The IMAPIFormMgr::CreateForm method launches a form to create a new message of the form's message class.

Quick Info

See IMAPIFormMgr : IUnknown.

HRESULT CreateForm(
  ULONG ulUIParam,
  ULONG ulFlags,
  IMAPIFormInfo pfrminfoToActivate,
  REFIID refiidToAsk,
  LPVOID FAR * ppvObj
);

Parameters

ulUIParam
[in] Handle to the parent window for the progress indicator displayed while the form is launched. The ulUIParam parameter is ignored unless the MAPI_DIALOG flag is set in the ulFlags parameter.
ulFlags
[in] Bitmask of flags that controls how the form is launched. The following flag can be set:
MAPI_DIALOG
Displays a user interface to provide status or prompt the user for additional information. If this flag is not set, no user interface is displayed.
pfrminfoToActivate
[in] Pointer to the form information object used to launch the form.
refiidToAsk
[in] Pointer to the interface identifier (IID) for the interface to be returned for the form object created. The refiidToAsk parameter must not be NULL.
ppvObj
[out] Pointer to a pointer to the returned interface.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_NO_INTERFACE
The requested interface is not supported by the form object.

Remarks

Form viewers call the IMAPIFormMgr::CreateForm method to launch a form to create a new message of the form's message class. CreateForm launches the form by creating an instance of the form server for that form as described in the given form information object. If required, CreateForm calls IMAPIFormMgr::PrepareForm to download the form server code to the user's disk.

The pfrminfoToActivate parameter must point to a form information object that has been correctly resolved.

After the form has been launched, the calling form viewer must set up a message using the IPersistMessage interface and can optionally set up a view context for the form. For more information, see Launching a Form Server.

See Also

IMAPIViewContext : IUnknown, IPersistMessage : IUnknown


IMAPIFormMgr::IsInConflict

The IMAPIFormMgr::IsInConflict method determines whether a form can handle its own message conflicts. A message is in conflict if it has been simultaneously edited by more than one user. This can happen to messages in public folders.

Quick Info

See IMAPIFormMgr : IUnknown.

HRESULT IsInConflict(
  ULONG ulMessageFlags,
  ULONG ulMessageStatus,
  LPCSTR szMessageClass
  LPMAPIFOLDER pFolderFocus
);

Parameters

ulMessageFlags
[in] Pointer to a bitmask of flags — copied from the PR_MESSAGE_FLAGS property of a message — that indicates the current state of the message.
ulMessageStatus
[in] Bitmask of client- or provider-defined flags — copied from the PR_MSG_STATUS property of a message — that provides further information on the state of the message.
szMessageClass
[in] String naming the message's message class.
pFolderFocus
[in] Pointer to the folder that contains the message. The pFolderFocus parameter can be NULL if such a folder doesn't exist — for example, in a case where the message is embedded in another message.

Return Values

S_OK
The form does not handle its own message conflicts.
S_FALSE
The form handles its own message conflicts, or the message for which information was passed is not in conflict.

Remarks

Form viewers call the IMAPIFormMgr::IsInConflict method to discover if a particular form does not handle its own message conflicts. IsInConflict checks the bitmasks in the ulMessageFlags and ulMessageStatus parameters for the presence of a conflict flag. If a conflict flag is set, IsInConflict resolves the message class passed in the szMessageClass parameter and returns S_OK if the form does not handle its own conflicts. IsInConflict returns S_FALSE if the form handles its own conflicts.

A form that does not handle its own conflicts must be launched using the IMAPIFormMgr::LoadForm method and cannot reuse an existing form object.

Notes to Callers

Client applications typically have to deal with conflicts when going from one message to the next or previous message in a folder. If a message is in conflict, but the form server for that message can handle conflicts, then the client application should execute its usual code for displaying the next or previous message. If the form server cannot handle conflicts, then the client application should proceed as if it was unaware of the message class of the next or previous message.

See Also

IMAPIFormAdviseSink::OnActivateNext, PR_MESSAGE_FLAGS, PR_MSG_STATUS


IMAPIFormMgr::LoadForm

The IMAPIFormMgr::LoadForm method launches a form to open an existing message.

Quick Info

See IMAPIFormMgr : IUnknown.

HRESULT LoadForm(
  ULONG ulUIParam,
  ULONG ulFlags,
  LPCSTR lpszMessageClass,
  ULONG ulMessageStatus,
  ULONG ulMessageFlags,
  LPMAPIFOLDER pFolderFocus,
  LPMAPIMESSAGESITE pMessageSite,
  LPMESSAGE pmsg,
  LPMAPIVIEWCONTEXT pViewContext,
  REFIID riid,
  LPVOID FAR * ppvObj
);

Parameters

ulUIParam
[in] Handle of the parent window for the progress indicator displayed while the form is launched. The ulUIParam parameter is ignored unless the MAPI_DIALOG flag is set in the ulFlags parameter.
ulFlags
[in] Bitmask of flags that controls how the form is launched. The following flags can be set:
MAPI_DIALOG
Displays a user interface to provide status or prompt the user for additional information. If this flag is not set, no user interface is displayed.
MAPIFORM_EXACTMATCH
Only message class strings that are an exact match should be resolved.
lpszMessageClass
[in] Pointer to a string naming the message class of the message to be loaded. If NULL is passed in the lpszMessageClass parameter, the message class is determined from the message pointed to by the pmsg parameter.
ulMessageStatus
[in] Bitmask of client- or provider-defined flags — copied from the PR_MSG_STATUS property of the message — that provides information on the state of the message. The ulMessageStatus parameter must be set if lpszMessageClass is non-null; otherwise, ulMessageStatus is ignored.
ulMessageFlags
[in] Pointer to a bitmask of flags — copied from the PR_MESSAGE_FLAGS property of the message — that indicates the current state of the message. The ulMessageFlags parameter must be set if lpszMessageClass is non-null; otherwise, ulMessageFlags is ignored.
pFolderFocus
[in] Pointer to the folder that directly contains the message. The pFolderFocus parameter can be NULL if such a folder doesn't exist — for example, if the message is embedded in another message.
pMessageSite
[in] Pointer to the message site of the message.
pmsg
[in] Pointer to the message.
pViewContext
[in] Pointer to the view context for the message. The pViewContext parameter can be NULL.
riid
[in] Interface identifier (IID) of the interface to be used for the returned form object. The refiidToAsk parameter must not be NULL.
ppvObj
[out] Pointer to a pointer to the returned interface.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_NO_INTERFACE
The form does not support the requested interface.
MAPI_E_NOT_FOUND
The message class passed in lpszMessageClass does not match the message class for any form in the form library.

Remarks

Form viewers call the IMAPIFormMgr::LoadForm method to launch a form for an existing message. LoadForm launches the form object, loads the message into the form object, sets up the appropriate view context if necessary, and returns the requested interface for the form object.

The pFolderFocus parameter points to the folder containing the message. If the message is embedded within another message, pFolderFocus should be NULL.

Notes to Implementers

If NULL is passed in lpszMessageClass, then the implementation obtains the message's message class, status, and flags from the message's PR_MESSAGE_CLASS, PR_MSG_STATUS and PR_MESSAGE_FLAGS properties. If a message class string is provided in lpszMessageClass, then the implementation must use the values in ulMessageStatus and ulMessageFlags.

See Also

PR_MESSAGE_FLAGS, PR_MSG_STATUS


IMAPIFormMgr::OpenFormContainer

The IMAPIFormMgr::OpenFormContainer method opens an IMAPIFormContainer interface for a specific form container.

Quick Info

See IMAPIFormMgr : IUnknown.

HRESULT OpenFormContainer(
  HFRMREG hfrmreg,
  LPUNKNOWN lpunk,
  LPMAPIFORMCONTAINER FAR * lppfcnt
);

Parameters

hfrmreg
[in] HFRMREG enumeration indicating the form library to open — that is, the form container to open. An HFRMREG enumeration is an enumeration specific to a form library provider. Possible HFRMREG values include:
HFRMREG_DEFAULT
Convenient form container.
HFRMREG_FOLDER
Folder container.
HFRMREG_PERSONAL
Container for the default message store.
HFRMREG_LOCAL
Local form container.
lpunk
[in] Pointer to the object for which the interface is opened. The lpunk parameter must be NULL unless the value for the hfrmreg parameter requires an object pointer.
lppfcnt
[out] Pointer to a pointer to the returned form container object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_NO_INTERFACE
The object pointed to by lpUnk does not support the required interface.

Remarks

Form viewers call the IMAPIFormMgr::OpenFormContainer method to open an IMAPIFormContainer interface for a specific form container. This interface can then be used for installing forms into and removing forms from a form container.

Notes to Callers

If the value in hfrmreg is HFRMREG_FOLDER, the interface identifier used in lpunk must be non-null and must allow QueryInterface calls to an IMAPIFolder interface.

To open the local form container, a call to OpenFormContainer or the MAPIOpenLocalFormContainer function must be used; the IMAPIFormMgr::SelectFormContainer method cannot be used to enable the user to select the local form container.

See Also

IMAPIFormContainer::InstallForm, IMAPIFormMgr::SelectFormContainer, MAPIOpenLocalFormContainer


IMAPIFormMgr::PrepareForm

The IMAPIFormMgr::PrepareForm method downloads a form for launching.

Quick Info

See IMAPIFormMgr : IUnknown.

HRESULT PrepareForm(
  ULONG ulUIParam,
  ULONG ulFlags,
  LPMAPIFORMINFO pfrmiInfo
);

Parameters

ulUIParam
[in] Handle of the parent window for the progress indicator displayed while the form is downloaded. The ulUIParam parameter is ignored unless the MAPI_DIALOG flag is set in the ulFlags parameter.
ulFlags
[in] Bitmask of flags that controls how the form is downloaded. The following flag can be set:
MAPI_DIALOG
Displays a user interface to provide status or prompt the user for additional information. If this flag is not set, no user interface is displayed.
pfrmiInfo
[in] Pointer to a form information object for the form to be downloaded.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Form viewers call the IMAPIFormMgr::PrepareForm method to download a form from a form container for launching. Most form viewers do not need to call PrepareForm because both the IMAPIFormMgr::CreateForm and IMAPIFormMgr::LoadForm methods call PrepareForm if necessary.

PrepareForm can be used to obtain the dynamic-link libraries (DLLs) and other files associated with a form in order to modify them. If the modified form is loaded back into its form container, it must be reinstalled.

See Also

IMAPIFormMgr::CreateForm, IMAPIFormMgr::LoadForm


IMAPIFormMgr::ResolveMessageClass

The IMAPIFormMgr::ResolveMessageClass method resolves a message class to its form within a form container and returns a form information object for that form.

Quick Info

See IMAPIFormMgr : IUnknown.

HRESULT ResolveMessageClass(
  LPCSTR szMsgClass,
  ULONG ulFlags,
  LPMAPIFOLDER pFolderFocus,
  LPMAPIFORMINFO FAR * ppResult
);

Parameters

szMsgClass
[in] String naming the message class being resolved.
ulFlags
[in] Bitmask of flags that controls how the message class is resolved. The following flag can be set:
MAPIFORM_EXACTMATCH
Only message class strings that are an exact match should be resolved.
pFolderFocus
[in] Pointer to the folder containing the message being resolved. The pFolderFocus parameter can be NULL.
ppResult
[out] Pointer to a pointer to a returned form information object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_NOT_FOUND
The message class passed in the szMsgClass parameter does not match the message class for any form in the form library.

Remarks

Form viewers call the IMAPIFormMgr::ResolveMessageClass method to resolve a message class to its form within a form container. The form information object returned in the ppResult parameter provides further access to the properties of the form with the given message class.

Notes to Callers

To resolve a message class to a form, a form viewer passes in the name of the message class to be resolved, such as "IPM.HelpDesk.Software".To force the resolution to be exact — that is, to prevent resolution to a superclass of the message class when an exactly matching form server is not available — the MAPIFORM_EXACTMATCH flag can be passed in the ulFlags parameter. If the pFolderFocus parameter is NULL, the message-class resolution process does not search a folder container.

The order of the containers searched depends on the implementation of the form library provider. The default form library provider searches first the local container, then the folder container for the passed-in folder, the personal form container, and finally the organization container.

Message class names are always ANSI strings, never Unicode.

The class identifier for the resolved message class is returned as part of the form information object. A form viewer should not work on the assumption that the class identifier exists in the OLE library until after the form viewer has called either the IMAPIFormMgr::PrepareForm method or the IMAPIFormMgr::CreateForm method.

See Also

IMAPIFormInfo : IMAPIProp, IMAPIFormMgr::CreateForm, IMAPIFormMgr::PrepareForm


IMAPIFormMgr::ResolveMultipleMessageClasses

The IMAPIFormMgr::ResolveMultipleMessageClasses method resolves a group of message classes to their forms within a form container and returns an array of form information objects for those forms.

Quick Info

See IMAPIFormMgr : IUnknown.

HRESULT ResolveMultipleMessageClasses(
  LPSMESSAGECLASSARRAY pMsgClasses,
  ULONG ulFlags,
  LPMAPIFOLDER pFolderFocus,
  LPSMAPIFORMINFOARRAY FAR * ppfrminfoarray
);

Parameters

pMsgClasses
[in] Pointer to an array containing the names of the message classes to resolve.
ulFlags
[in] Bitmask of flags that controls how the message classes are resolved. The following flag can be set:
MAPIFORM_EXACTMATCH
Only message class strings that are an exact match should be resolved.
pFolderFocus
[in] Pointer to the folder containing the form whose message class is being resolved. The pFolderFocus parameter can be NULL.
ppfrminfoarray
[out] Pointer to a pointer to an array of form information objects. If a form viewer passes NULL in the pMsgClasses parameter, the ppfrminfoarray parameter contains form information objects for all forms in the container.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Form viewers call the IMAPIFormMgr::ResolveMultipleMessageClasses method to resolve a group of message classes to forms within a form container. The array of form information objects returned in ppfrminfoarray provides further access to each of the forms' properties.

Notes to Callers

To resolve a group of message classes to forms, a form viewer passes in an array of message class names to be resolved. To force the resolution to be exact — that is, to prevent resolution to a superclass of the message class when an exactly matching form server is not available — the MAPIFORM_EXACTMATCH flag can be passed in the ulFlags parameter.

Message class names are always ANSI strings, never Unicode.

If a message class cannot be resolved to a form, NULL is returned for that message class in the form information array. Therefore, even if the method returns S_OK, form viewers should not work on the assumption that all message classes have been successfully resolved. Instead, form viewers should check the values in the returned array.

See Also

IMAPIFormMgr::ResolveMessageClass


IMAPIFormMgr::SelectForm

The IMAPIFormMgr::SelectForm method presents a dialog box that enables the user to select a form and returns a form information object describing that form.

Quick Info

See IMAPIFormMgr : IUnknown.

HRESULT SelectForm(
  ULONG ulUIParam,
  ULONG ulFlags,
  LPCTSTR pszTitle,
  LPMAPIFOLDER pfld,
  LPMAPIFORMINFO FAR * ppfrminfoReturned
);

Parameters

ulUIParam
[in] Handle of the parent window for the dialog box displayed.
ulFlags
[in] Bitmask of flags that controls the type of the passed-in strings. The following flag can be set:
MAPI_UNICODE
The passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
pszTitle
[in] Pointer to a string containing the caption of the dialog box. If the pszTitle parameter is NULL, the form library provider supplies a default caption.
pfld
[in] Pointer to the folder from which to select the form. If the pfld parameter is NULL, the form can be selected from the local, personal, or organization form container.
ppfrminfoReturned
[out] Pointer to a pointer to the returned form information object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.
MAPI_E_USER_CANCEL
The user canceled the operation, typically by clicking the Cancel button in the dialog box.

Remarks

Form viewers call the IMAPIFormMgr::SelectForm method to first present a dialog box that enables the user to select a form and then to retrieve a form information object describing the selected form. The dialog box constrains the user to select a single form.

Notes to Callers

The SelectForm dialog box only displays forms that are not hidden — that is, that have their hidden properties clear. If a form viewer passes the MAPI_UNICODE flag in the ulFlags parameter, all strings are Unicode. Form library providers that do not support Unicode strings should return MAPI_E_BAD_CHARWIDTH if MAPI_UNICODE is passed.


IMAPIFormMgr::SelectFormContainer

The IMAPIFormMgr::SelectFormContainer method presents a dialog box that enables the user to select a form container and returns an interface for the container object the user selected.

Quick Info

See IMAPIFormMgr : IUnknown.

HRESULT SelectFormContainer(
  ULONG ulUIParam,
  ULONG ulFlags,
  LPMAPIFORMCONTAINER FAR * lppfcnt
);

Parameters

ulUIParam
[in] Handle of the parent window for the dialog box displayed.
ulFlags
[in] Bitmask of flags that controls how the form library is selected — that is, how the form container is selected. The following flags can be set:
MAPIFORM_SELECT_ALL_REGISTRIES
Selection can be made from all containers. This type of selection is the default.
MAPIFORM_SELECT_FOLDER_REGISTRY_ONLY
Selection can be made only from folder containers.
MAPIFORM_SELECT_NON_FOLDER_REGISTRY_ONLY
Selection can be made only from containers not associated with folders.
lppfcnt
[out] Pointer to a pointer to the returned interface. This interface is for the container object selected by the user.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Form viewers commonly call the IMAPIFormMgr::SelectFormContainer method to select a form container into which a form is installed. SelectFormContainer cannot be used to select the local form container, which has the value HFRMREG_LOCAL.


IMAPIFormMgr::SelectMultipleForms

The IMAPIFormMgr::SelectMultipleForms method presents a dialog box that enables the user to select multiple forms and returns an array of form information objects describing those forms.

Quick Info

See IMAPIFormMgr : IUnknown.

HRESULT SelectMultipleForms(
  ULONG ulUIParam,
  ULONG ulFlags,
  LPCTSTR pszTitle,
  LPMAPIFOLDER pfld,
  LPMAPIFORMINFOARRAY pfrminfoarray,
  LPMAPIFORMINFOARRAY FAR * ppfrminfoarray
)

Parameters

ulUIParam
[in] Handle of the parent window for the dialog box displayed.
ulFlags
[in] Bitmask of flags that controls the type of the passed-in strings. The following flag can be set:
MAPI_UNICODE
The passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
pszTitle
[in] Pointer to a string containing the caption of the dialog box. If the pszTitle parameter is NULL, the form library provider that provides the forms supplies a default caption.
pfld
[in] Pointer to the folder from which to select the forms. If the pfld parameter is NULL, the forms are selected from the local, personal, or organization form container.
pfrminfoarray
[in] Pointer to an array of form information objects that are preselected for the user.
ppfrminfoarray
[out] Pointer to a pointer to the returned array of form information objects.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.
MAPI_E_USER_CANCEL
The user canceled the operation, typically by clicking the Cancel button in the dialog box.

Remarks

Form viewers call the IMAPIFormMgr::SelectMultipleForms method to first present a dialog box that enables the user to select multiple forms and then to retrieve an array of form information objects describing the selected forms. The SelectMultipleForms dialog box displays all forms, whether or not they are hidden — that is, whether or not their hidden properties are clear.

Notes to Implementers

If a form viewer passes the MAPI_UNICODE flag in the ulFlags parameter, all strings are Unicode. Form library providers that do not support Unicode strings should return MAPI_E_BAD_CHARWIDTH if MAPI_UNICODE is passed.


IMAPIMessageSite : IUnknown

The IMAPIMessageSite interface manipulates messages and is implemented by the form viewer code—typically a client application—that responds to such manipulation.

Quick Info

Header file: | MAPIFORM.H
Exposed by: | Message site objects
Implemented by: | Form viewers
Called by: | Form objects
Interface identifier: | IID_IMAPIMessageSite
Pointer type: | LPMAPIMESSAGESITE

Vtable Order

GetSession | Returns the MAPI session in which the current message was created or opened.
GetStore | Returns the message store containing the current message, if such a store exists. GetStore will return NULL for messages that are embedded in another message.
GetFolder | Returns the folder in which the current message was created or opened, if such a folder exists. GetFolder will return NULL for messages that are embedded in another message.
GetMessage | Returns the current message.
GetFormManager | Returns a form manager interface, which a form server can use to launch another form server.
NewMessage | Creates a new message.
CopyMessage | Copies the current message to a folder.
MoveMessage | Moves the current message to a folder.
DeleteMessage | Deletes the current message.
SaveMessage | Requests that the current message be saved.
SubmitMessage | Requests that the current message be submitted to the MAPI spooler for delivery.
GetSiteStatus | Returns information from a message site object about the message site's capabilities for the current message.


IMAPIMessageSite::CopyMessage

The IMAPIMessageSite::CopyMessage method copies the current message to a folder.

Quick Info

See IMAPIMessageSite : IUnknown.

HRESULT CopyMessage(
  LPMAPIFOLDER pFolderDestination
);

Parameters

pFolderDestination
[in] Pointer to the folder where the message is copied.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_NO_SUPPORT
The operation is not supported by this message site.

Remarks

Form objects call the IMAPIMessageSite::CopyMessage method to copy the current message to a new folder. CopyMessage does not change the message currently being displayed to the user, and no interface for the newly created message is returned to the form.

Notes to Implementers

A typical implementation of CopyMessage:

  1. Creates the new message the current message is copied to.
  2. Calls the IPersistMessage::Save method with a pointer to the new message in the pMessage parameter and FALSE in the fSameAsLoad parameter.
  3. Calls the IPersistMessage::SaveCompleted method passing NULL for its pMessage parameter.
  4. Calls the IMAPIProp::SaveChanges method on the new message.

For a list of interfaces related to form servers, see MAPI Form Interfaces.

See Also

IMAPIProp::SaveChanges, IPersistMessage::Save, IPersistMessage::SaveCompleted


IMAPIMessageSite::DeleteMessage

The IMAPIMessageSite::DeleteMessage method deletes the current message.

Quick Info

See IMAPIMessageSite : IUnknown.

HRESULT DeleteMessage(
  LPMAPIVIEWCONTEXT pViewContext,
  LPCRECT prcPosRect
);

Parameters

pViewContext
[in] Pointer to a view context object.
prcPosRect
[in] Pointer to a RECT structure containing the current form's window size and position. The next form displayed also uses this window rectangle.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_NO_SUPPORT
The operation is not supported by this message site.

Remarks

A form object calls the IMAPIMessageSite::DeleteMessage method to delete the message the form is currently displaying.

Notes to Callers

Following the return of DeleteMessage, form objects must check for a new message and then dismiss themselves if none exists. To determine whether the message DeleteMessage acted on is deleted or moved to a Deleted Items folder, a form object can call the IMAPIMessageSite::GetSiteStatus method and check if the DELETE_IS_MOVE flag was returned.

Notes to Implementers

If a form viewer's implementation of DeleteMessage moves to the next message after deleting a message, it should call the IMAPIViewContext::ActivateNext method passing the VCDIR_DELETE flag prior to performing the actual deletion. If a form viewer's implementation of DeleteMessage moves the deleted message, for example to a Deleted Items folder, it must save changes to the message if the message has been modified.

A typical implementation of DeleteMessage:

  1. If moving the message, calls the IPersistMessage::Save method passing NULL for its pMessage parameter and TRUE for its fSameAsLoad parameter.
  2. Calls the IMAPIViewContext::ActivateNext method passing the VCDIR_DELETE flag in its ulDir parameter.
  3. If the ActivateNext call fails, it returns. If ActivateNext returns S_FALSE, it calls the IPersistMessage::HandsOffMessage method.
  4. Deletes or moves the message.

To obtain the RECT structure used by a form's window, call the Windows GetWindowRect function.

For a list of interfaces related to form servers, see MAPI Form Interfaces.

See Also

IMAPIMessageSite::GetSiteStatus, IMAPIViewContext::ActivateNext, IPersistMessage::HandsOffMessage, IPersistMessage::Save


IMAPIMessageSite::GetFolder

The IMAPIMessageSite::GetFolder method returns the folder in which the current message was created or opened, if such a folder exists. This method returns NULL in the ppFolder parameter for embedded messages, which are not stored directly in a folder.

Quick Info

See IMAPIMessageSite : IUnknown.

HRESULT GetFolder(
  LPMAPIFOLDER FAR * ppFolder
);

Parameters

ppFolder
[out] Pointer to a pointer to the returned folder.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
S_FALSE
No folder exists for the message.

Remarks

For a list of interfaces related to form servers, see MAPI Form Interfaces.


IMAPIMessageSite::GetFormManager

The IMAPIMessageSite::GetFormManager method returns a form manager interface, which a form server can use to launch another form server.

Quick Info

See IMAPIMessageSite : IUnknown.

HRESULT GetFormManager(
  LPMAPIFORMMGR FAR * ppFormMgr
);

Parameters

ppFormMgr
[out] Pointer to a pointer to the returned form manager interface.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

For a list of interfaces related to form servers, see MAPI Form Interfaces.


IMAPIMessageSite::GetMessage

The IMAPIMessageSite::GetMessage method returns the current message.

Quick Info

See IMAPIMessageSite : IUnknown.

HRESULT GetMessage(
  LPMESSAGE FAR * ppmsg
);

Parameters

ppmsg
[out] Pointer to a pointer to the returned interface for the message.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
S_FALSE
No message currently exists for the calling form.

Remarks

Forms call the IMAPIMessageSite::GetMessage method to obtain a message interface for the current message. The current message is the same message as was previously passed in the IPersistMessage::InitNew, IPersistMessage::Load, or IPersistMessage::SaveCompleted method.

GetMessage returns S_FALSE if no message currently exists. This state can occur after calls to the IPersistMessage::HandsOffMessage method or before the next call to IPersistMessage::Load or IPersistMessage::SaveCompleted is made.

For a list of interfaces related to form servers, see MAPI Form Interfaces.

See Also

IPersistMessage : IUnknown


IMAPIMessageSite::GetSession

The IMAPIMessageSite::GetSession method returns the MAPI session in which the current message was created or opened.

Quick Info

See IMAPIMessageSite : IUnknown.

HRESULT GetSession(
  LPMAPISESSION FAR * ppSession
);

Parameters

ppSession
[out] Pointer to a pointer to the returned session object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
S_FALSE
No session exists for the current message.

Remarks

For a list of interfaces related to form servers, see MAPI Form Interfaces.


IMAPIMessageSite::GetSiteStatus

The IMAPIMessageSite::GetSiteStatus method returns information from a message site object about the message site's capabilities for the current message.

Quick Info

See IMAPIMessageSite : IUnknown.

HRESULT GetSiteStatus(
  ULONG FAR * lpulStatus
);

Parameters

lpulStatus
[out] Pointer to a bitmask of flags giving information on message status. The following flags can be set:
VCSTATUS_COPY
The message can be copied.
VCSTATUS_DELETE
The message can be deleted.
VCSTATUS_DELETE_IS_MOVE
When deleted, a message is actually moved to a Deleted Items folder in its message store rather than being immediately removed from its message store.
VCSTATUS_MOVE
The message can be moved.
VCSTATUS_NEW_MESSAGE
A new message can be created.
VCSTATUS_SAVE
The message can be saved.
VCSTATUS_SUBMIT
The message can be submitted.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Form objects call the IMAPIMessageSite::GetSiteStatus method to obtain the message site object's capabilities for the current message. The flags returned in the lpulStatus parameter provide information on the message site; typically, a form enables or disables menu commands based on information the flags provide on the capabilities of the message site implementation. If a new message is loaded into a form by the IPersistMessage::SaveCompleted method or the IPersistMessage::Load method, the status flags must be checked. Some message site objects, particularly read-only ones, do not permit messages to be saved or deleted.

Notes to Implementers

IMAPIMessageSite::GetSiteStatus may require your client application to do some calculation to determine what operations can and can't be performed on the current message. Typically, that involves looking at the status row for the current message's message store provider, or querying the store provider directly to determine which actions the client application can perform using the message store. For example, determining whether to return the MAPI_DELETE_IS_MOVE flag could be done by checking the message store object's PR_IPM_WASTEBASKET_ENTRYID property to see whether there is a Deleted Items folder in the message store.

For a list of interfaces related to form servers, see MAPI Form Interfaces.

See Also

IPersistMessage::Load, IPersistMessage::SaveCompleted


IMAPIMessageSite::GetStore

The IMAPIMessageSite::GetStore method returns the message store containing the current message, if such a store exists. This method will return NULL in the ppStore parameter for embedded messages, which are stored within another message rather than directly in a message store.

Quick Info

See IMAPIMessageSite : IUnknown.

HRESULT GetStore(
  LPMDB FAR * ppStore
);

Parameters

ppStore
[out] Pointer to a pointer to the message store.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
S_FALSE
There is no store containing the message.

Remarks

For a list of interfaces related to form servers, see MAPI Form Interfaces.


IMAPIMessageSite::MoveMessage

The IMAPIMessageSite::MoveMessage method moves the current message to a folder.

Quick Info

See IMAPIMessageSite : IUnknown.

HRESULT MoveMessage(
  LPFOLDER pFolderDestination,
  LPMAPIVIEWCONTEXT pViewContext,
  LPCRECT prcPosRect
);

Parameters

pFolderDestination
[in] Pointer to the folder where the message is moved.
pViewContext
[in] Pointer to a view context object.
prcPosRect
[in] Pointer to a RECT structure containing the current form's window size and position. The next form displayed also uses this window rectangle.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_NO_SUPPORT
The operation is not supported by this message site.

Remarks

Form objects call the IMAPIMessageSite::MoveMessage method to move the current message to a new folder.

Notes to Implementers

A form viewer's implementation of MoveMessage must call the IMAPIViewContext::ActivateNext method, passing the VCDIR_MOVE flag, prior to actually moving the message to a new folder. To obtain the RECT structure used by a form's window, call the Windows GetWindowRect function.

For a list of interfaces related to form servers, see MAPI Form Interfaces.

Notes to Callers

Following the return of MoveMessage, forms must check for a current message and then dismiss themselves if none exists.

See Also

IMAPIViewContext::ActivateNext


IMAPIMessageSite::NewMessage

The IMAPIMessageSite::NewMessage method creates a new message.

Quick Info

See IMAPIMessageSite : IUnknown.

HRESULT NewMessage(
  ULONG fComposeInFolder,
  LPMAPIFOLDER pFolderFocus,
  LPPERSISTMESSAGE pPersistMessage,
  LPMESSAGE FAR * ppMessage,
  LPMAPIMESSAGESITE FAR * ppMessageSite,
  LPMAPIVIEWCONTEXT FAR * ppViewContext
);

Parameters

fComposeInFolder
[in] Variable indicating in which folder the message should be composed. If the variable is FALSE, the pFolderFocus parameter is ignored and the form viewer can compose the message in any folder. If the variable is TRUE and NULL is passed in pFolderFocus, the message is composed in the current folder. If the variable is TRUE and a non-null value is passed in pFolderFocus, the message is composed in the folder pointed to by pFolderFocus.
pFolderFocus
[in] Pointer to the folder where the new message is created.
pPersistMessage
[in] Pointer to the form object for the new form.
ppMessage
[out] Pointer to a pointer to the new message.
ppMessageSite
[out] Pointer to a pointer to a message site object for the new message.
ppViewContext
[out] Pointer to a pointer to a view context appropriate for passing to a new form with the new message. If the form implements its own view context, NULL can be passed in the ppViewContext parameter.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Form objects call the IMAPIMessageSite::NewMessage method to create a new message. The form uses NewMessage to get a new message and the associated message site from its view. It can then modify the new message.

An associated view context can also be obtained by passing in a non-null value in the ppViewContext parameter. This view context can be used directly, or it can be aggregated and passed to the new message. If a complete implementation is required, NULL should be passed in ppViewContext.

For a list of interfaces related to form servers, see MAPI Form Interfaces.

See Also

IMAPIViewContext : IUnknown


IMAPIMessageSite::SaveMessage

The IMAPIMessageSite::SaveMessage method requests that the current message be saved.

Quick Info

See IMAPIMessageSite : IUnknown.

HRESULT SaveMessage();

Parameters

None.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Forms call the IMAPIMessageSite::SaveMessage method to request that a message be saved.

For a list of interfaces related to form servers, see MAPI Form Interfaces.


IMAPIMessageSite::SubmitMessage

The IMAPIMessageSite::SubmitMessage method requests that the current message be submitted to the MAPI spooler.

Quick Info

See IMAPIMessageSite : IUnknown.

HRESULT SubmitMessage(
  ULONG ulFlags
);

Parameters

ulFlags
[in] Bitmask of flags that controls how a message is submitted. The following flag can be set:
FORCE_SUBMIT
MAPI should submit the message even if it might not be sent right away.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Form objects call the IMAPIMessageSite::SubmitMessage method to request that a message be submitted to the MAPI spooler. The message site should call the IPersistMessage::HandsOffMessage method prior to submitting the message. The message need not have previously been saved, as SubmitMessage should cause the message to be saved if it has been modified. Following the return of SubmitMessage, the form must check for a current message and then dismiss itself if none exists.

For a list of interfaces related to form servers, see MAPI Form Interfaces.

See Also

IPersistMessage::HandsOffMessage


IMAPIProgress : IUnknown

The IMAPIProgress interface is used to implement a progress object — an object for providing client applications with a progress indicator. A progress indicator is a user interface display that shows the percentage of completion of an operation, such as copying folders between message stores. MAPI and client applications implement progress objects and service providers use them.

Quick Info

Header file: | MAPIDEFS.H
Exposed by: | Progress objects
Implemented by: | MAPI and client applications
Called by: | Service providers
Interface identifier: | IID_IMAPIProgress
Pointer type: | LPMAPIPROGRESS

Vtable Order

Progress | Updates the progress indicator with status on the progress made toward completion of the operation in question.
GetFlags | Returns flag settings from the progress object for the level of operation on which progress information is calculated.
GetMax | Returns the maximum number of items in the operation for which progress information is displayed.
GetMin | Returns the minimum number of items in the operation for which progress information is displayed.
SetLimits | Sets the minimum number of items operated on, the maximum number of items operated on, and the flags that control how progress information is calculated for the operation in question.

Remarks

MAPI includes an lpProgress parameter in many of the methods that perform potentially lengthy operations. The lpProgress parameter points to a client implementation of a progress object. Clients that implement IMAPIProgress set this parameter to point to their implementation; clients that do not implement IMAPIProgress set it to NULL. To display a progress indicator during processing of the operation, service providers use the progress object supplied by the client if possible or a MAPI implementation if lpProgress is set to NULL.


IMAPIProgress::GetFlags

The IMAPIProgress::GetFlags method returns flag settings from the progress object for the level of operation on which progress information is calculated.

Quick Info

See IMAPIProgress : IUnknown.

HRESULT GetFlags(
  ULONG FAR * lpulFlags
);

Parameters

lpulFlags
[out] Bitmask of flags that controls the level of operation on which progress information is calculated. The following flag can be returned:
MAPI_TOP_LEVEL
Progress is being calculated for the top-level object — the object that is called by the client to begin the operation. For example, the top-level object in a folder copy operation is the folder being copied.

When MAPI_TOP_LEVEL is not set, progress is being calculated for a lower level object, or subobject. In the folder copy operation, a lower level object would be one of the subfolders in the folder being copied.

Return Values

S_OK
The flags value was returned successfully.

Remarks

MAPI allows service providers to differentiate between top-level objects and subobjects with the MAPI_TOP_LEVEL flag so that all objects involved in an operation can use the same IMAPIProgress implementation to show progress, thereby causing the indicator display to proceed smoothly in a single positive direction. Whether or not the MAPI_TOP_LEVEL flag is set determines how service providers set the other parameters in subsequent calls to the progress object.

The value returned by GetFlags is set initially by the implementer and subsequently by the service provider through a call to IMAPIProgress:SetLimits.

Notes to Implementers

Always initialize the flag to MAPI_TOP_LEVEL and then rely on service providers to clear it when appropriate. Service providers can clear and reset the flag by calling IMAPIProgress::SetLimits. For more information about implementing GetFlags and the other IMAPIProgress methods, see Implementing a Progress Indicator.

Notes to Callers

When displaying a progress indicator, make your first call a call to IMAPIProgress::GetFlags. The value returned should be MAPI_TOP_LEVEL because all implementations initialize the contents of lpulFlags to this value. For more information about the sequence of calls to a progress object, see Displaying Progress Step by Step.

See Also

IMAPIProgress::SetLimits


IMAPIProgress::GetMax

The IMAPIProgress::GetMax method returns the maximum number of items in the operation for which progress information is displayed.

Quick Info

See IMAPIProgress : IUnknown.

HRESULT GetMax(
  ULONG FAR * lpulMax
);

Parameters

lpulMax
[out] Pointer to the maximum number of items in the operation.

Return Values

S_OK
The maximum number of items in the operation has been retrieved.

Remarks

The maximum value represents the end of the operation in numeric form. The value can be a global maximum value, used to represent the scope of the entire progress display, or a local value, used to represent only a part of the display.

The value of the flags setting affects whether the progress object understands the maximum value to be local or global. When the MAPI_TOP_LEVEL flag is set, the maximum value is considered to be global and is used to calculate progress for the entire operation. When MAPI_TOP_LEVEL is not set, the maximum value is considered local and is used internally by providers to display progress for lower level subobjects. Progress objects save the local maximum value only to return it to a provider through a GetMax call.

For more information about how and when to make calls to a progress object, see Displaying Progress Step by Step.

Notes to Implementers

Initialize the maximum value to 1000. Service providers can reset this value by calling IMAPIProgress::SetLimits. For more information about implementing GetMax and the other IMAPIProgress methods, see Implementing a Progress Indicator.

See Also

IMAPIProgress::GetMin, IMAPIProgress::Progress, IMAPIProgress::SetLimits


IMAPIProgress::GetMin

The IMAPIProgress::GetMin method returns the minimum value in IMAPIProgress::SetLimits for which progress information is displayed.

Quick Info

See IMAPIProgress : IUnknown.

HRESULT GetMin(
  ULONG FAR * lpulMin
);

Parameters

lpulMin
[out] Pointer to the minimum number of items in the operation.

Return Values

S_OK
The minimum number of items in the operation has been retrieved.

Remarks

The minimum value represents the beginning of the operation in numeric form. The value can be a global maximum value, used to represent the scope of the entire progress display, or a local value, used to represent only a part of the display.

The value of the flags setting affects whether the progress object understands the minimum value to be local or global. When the MAPI_TOP_LEVEL flag is set, the minimum value is considered to be global and is used to calculate progress for the entire operation. When MAPI_TOP_LEVEL is not set, the minimum value is considered local and is used internally by providers to display progress for lower level subobjects. Progress objects save the local minimum value only to return it to a provider through a GetMin call.

Notes to Implementers

Initialize the minimum value to 1. Service providers can reset this value by calling IMAPIProgress::SetLimits. For more information about implementing GetMin and the other IMAPIProgress methods, see Implementing a Progress Indicator.

For more information about how and when to make calls to a progress object, see Displaying Progress Step by Step.

See Also

IMAPIProgress::GetMax, IMAPIProgress::Progress, IMAPIProgress::SetLimits


IMAPIProgress::Progress

The IMAPIProgress::Progress method updates the progress indicator with a display of the progress as it is made toward completion of the operation.

Quick Info

See IMAPIProgress : IUnknown.

HRESULT Progress(
  ULONG ulValue,
  ULONG ulCount,
  ULONG ulTotal
);

Parameters

ulValue
[in] Number indicating the current level of progress, calculated from the ulCount and ulTotal parameters or from the lpulMin and lpulMax parameters of the IMAPIProgress::SetLimits method between the global lower limit and the global upper limit.
ulCount
[in] Number indicating the currently processed item relative to the total.
ulTotal
[in] Total number of items to be processed during the operation.

Return Values

S_OK
The progress indicator was successfully updated.

Notes to Implementers

The ulValue parameter will be equal to the global minimum value only at the beginning of the operation and to the global maximum value only at the completion of the operation.

Use the second and third parameters, ulCount and ulTotal, if available, to display an optional message such as "5 items completed out of 10." If the second and third parameters are set to zero, choose whether or not to visually change the progress indicator. Some service providers set these parameters to zeroes to indicate that they are processing a subobject whose progress is monitored relative to a parent object. In this situation, it makes sense to change the display only when the parent object reports progress. Some service providers pass zeroes for these parameters every time.

For more information about implementing Progress and the other IMAPIProgress methods, see Implementing a Progress Indicator.

Notes to Callers

Not all three of the parameters to IMAPIProgress::Progress are required. The only parameter that is required is the first value, a number that indicates percentage of progress. If the MAPI_TOP_LEVEL flag is set, you can also pass an object count and an object total. Some implementations use these values to display a phrase such as "5 items completed out of 10" with the progress indicator.

If you are copying all messages within a single folder, set ulTotal to the total number of messages being copied. If you are copying a folder, set ulTotal to the number of subfolders within the folder. If the folder to be copied contains no subfolders and only messages, set ulTotal to 1.

For more information about how and when to make calls to a progress object, see Displaying Progress Step by Step.

See Also

IMAPIProgress::SetLimits


IMAPIProgress::SetLimits

The IMAPIProgress::SetLimits method sets the lower limit for the number of items operated on, the maximum number of items operated on, and the flags that control how progress information is calculated for the operation in question.

Quick Info

See IMAPIProgress : IUnknown.

HRESULT SetLimits(
  LPULONG lpulMin,
  LPULONG lpulMax,
  LPULONG lpulFlags
);

Parameters

lpulMin
[in] Pointer to a variable containing the lower limit of items in the operation.
lpulMax
[in] Pointer to a variable containing the upper limit of items in the operation.
lpulFlags
[in] Bitmask of flags that controls the level of operation on which progress information is calculated. The following flag can be set:
MAPI_TOP_LEVEL
Uses the values in the IMAPIProgress::Progress method's ulCount and ulTotal parameters, which indicate the item being operated on and the total items, respectively, to increment progress on the operation. When this flag is set, the values of the global lower and upper limits have to be set.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Service providers call IMAPIProgress::SetLimits to set or clear the MAPI_TOP_LEVEL flag and to set local and global minimum and maximum values. The value of the flags setting affects whether the progress object understands the minimum and maximum values to be local or global. When the MAPI_TOP_LEVEL flag is set, these values are considered global and are used to calculate progress for the entire operation. Progress objects initialize the global minimum value to 1 and the global maximum value to 1000.

When MAPI_TOP_LEVEL is not set, the minimum and maximum values are considered local and are used internally by providers to display progress for lower level subobjects. Progress objects save the local minimum and maximum values only so that they can be returned to providers when GetMin and GetMax are called.

For more information about implementing SetLimits and the other IMAPIProgress methods, see Implementing a Progress Indicator.

For more information about how and when to make calls to a progress object, see Displaying Progress Step by Step.

See Also

IMAPIProgress::Progress


IMAPIProp : IUnknown

The IMAPIProp interface is implemented by all objects that support properties. It is used by clients, service providers, and MAPI to work with properties.

Quick Info

Header file: | MAPIDEFS.H
Exposed by: | No object exposes this interface directly.
Implemented by: | Service providers and MAPI
Called by: | Client applications, service providers, and MAPI
Interface identifier: | IID_IMAPIProp
Pointer type: | LPMAPIPROP
Transaction model: | Abstract class, never implemented

Vtable Order

GetLastError | Returns a MAPIERROR structure containing information about the previous error.
SaveChanges | Makes permanent any changes made to an object since the last save operation.
GetProps | Retrieves one or more properties.
GetPropList | Returns property tags for all properties.
OpenProperty | Returns a pointer to an interface to be used to access a property.
SetProps | Updates one or more properties.
DeleteProps | Deletes one or more properties.
CopyTo | Copies or moves all properties, except for specifically excluded properties.
CopyProps | Copies or moves selected properties.
GetNamesFromIDs | Provides the property names that correspond to one or more property identifiers.
GetIDsFromNames | Provides the property identifiers that correspond to one or more property names.

Remarks

IMAPIProp is the base interface for the following interfaces:

IAttach

IMailUser

IMAPIContainer

IMAPIFormInfo

IMAPIStatus

IMessage

IMsgStore

IProfSect

IPropData


IMAPIProp::CopyProps

The IMAPIProp::CopyProps method copies or moves selected properties.

Quick Info

See IMAPIProp : IUnknown.

HRESULT CopyProps(
  LPSPropTagArray lpIncludeProps,
  ULONG ulUIParam,
  LPMAPIPROGRESS lpProgress,
  LPCIID lpInterface,
  LPVOID lpDestObj,
  ULONG ulFlags,
  LPSPropProblemArray FAR * lppProblems
);

Parameters

lpIncludeProps
[in] Pointer to a property tag array specifying the properties to copy or move. PR_NULL cannot be included in the array. The lpIncludeProps parameter cannot be NULL.
ulUIParam
[in] Handle of the parent window for the progress indicator.
lpProgress
[in] Pointer to an implementation of a progress indicator. If NULL is passed in the lpProgress parameter, the progress indicator is displayed using the MAPI implementation. The lpProgress parameter is ignored unless the MAPI_DIALOG flag is set in the ulFlags parameter.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the object pointed to by lpDestObj. The lpInterface parameter must not be NULL.
lpDestObj
[in] Pointer to the object to receive the copied or moved properties.
ulFlags
[in] Bitmask of flags that controls the copy or move operation. The following flags can be set:
MAPI_DECLINE_OK
If CopyProps calls the IMAPISupport::DoCopyProps method to handle the copy or move operation, it should instead return immediately with the error value MAPI_E_DECLINE_COPY. The MAPI_DECLINE_OK flag is set by MAPI to limit recursion. Clients do not set this flag.
MAPI_DIALOG
Allows the display of a progress indicator.
MAPI_MOVE
CopyProps should perform a move operation rather than a copy operation. When this flag is not set, CopyProps performs a copy operation.
MAPI_NOREPLACE
Existing properties in the destination object should not be overwritten. When this flag is not set, CopyProps overwrites existing properties.
lppProblems
[in, out] On input, can be NULL, indicating no need for error information, or a pointer to a pointer to an SPropProblemArray structure. If lppProblems is a valid pointer on input, CopyProps returns detailed information about errors in copying one or more properties.

Return Values

S_OK
Properties have been successfully copied or moved.
MAPI_E_COLLISION
A subobject cannot be copied because there is already a subobject existing in the destination object with the same display name (PR_DISPLAY_NAME property) as the subobject to be copied.
MAPI_E_DECLINE_COPY
The service provider does not implement the copy operation.
MAPI_E_FOLDER_CYCLE
The source object performing the copy or move operation directly or indirectly contains the destination object. Significant work might have been performed before this condition was discovered, so the source and destination objects might be partially modified.
MAPI_E_INTERFACE_NOT_SUPPORTED
The interface identified by the lpInterface parameter is not supported by the destination object.
MAPI_E_NO_ACCESS
An attempt was made to access an object for which the caller has insufficient permissions. This error is returned if the destination object is the same as the source object.

The following values can be returned in the SPropProblemArray structure, but not as return values for CopyProps. These errors apply to a single property:

MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and CopyProps does not support Unicode, or MAPI_UNICODE was not set and CopyProps only supports Unicode.
MAPI_E_COMPUTED
The property cannot be modified by the caller because it is a read-only property, computed by the owner of the destination object. This error is not severe; the caller should allow the copy operation to continue.
MAPI_E_INVALID_TYPE
The property type is invalid.
MAPI_E_UNEXPECTED_TYPE
The property type is not the type expected by the caller.

Remarks

The IMAPIProp::CopyProps method copies or moves selected properties from the current object to a destination object. CopyProps is used mainly for replying to and forwarding messages, where only some of the properties from the original message travel with the reply or forwarded copy.

Any subobjects in the source object are automatically included in the operation and copied or moved in their entirety, regardless of the use of properties indicated by the SPropTagArray structure. By default, CopyProps overwrites any properties in the destination object that match properties from the source object. If any of the copied or moved properties already exist in the destination object, the existing properties are overwritten by the new, unless the MAPI_NOREPLACE flag is set in the ulFlags parameter. Existing information in the destination object that is not overwritten is left untouched.

Notes to Implementers

You can provide a full implementation of CopyProps or rely on the implementation that MAPI provides in its support object. If you want to use the MAPI implementation, call IMAPISupport::DoCopyProps. However, If you do delegate processing to DoCopyProps and you are passed the MAPI_DECLINE_OK flag, avoid the support call and return MAPI_E_DECLINE_COPY instead. You will be called with this flag by MAPI to avoid the possible recursion that can happen when copying folders.

Because the copy operation can be lengthy, you are encouraged to display a progress indicator. Use the IMAPIProgress implementation passed in the lpProgress parameter, if there is one. If lpProgress is NULL, call IMAPISupport::DoProgressDialog to use the MAPI implementation.

Notes to Callers

Do not set the MAPI_DECLINE_OK flag; it is used by MAPI in its calls to message store provider CopyProps implementations.

Because copy and move operations can take time, it is wise to request the display of a progress indicator by setting the MAPI_DIALOG flag. You can set the lpProgress parameter to your implementation of IMAPIProgress, if you have one, or to NULL. If lpProgress is NULL, CopyProps will use the default progress indicator provided by MAPI.

You can suppress the display of a progress indicator by not setting the MAPI_DIALOG flag. CopyProps will ignore the ulUIParam and lpProgress parameters and avoid displaying the indicator.

CopyProps can report global and individual errors, or errors that occur with one or more of the properties. These individual errors are placed in an SPropProblemArray structure. You can suppress error reporting at the property level by passing NULL for the property problem array structure parameter rather than a valid pointer.

If you want to receive information about errors, pass a valid SPropProblemArray structure pointer in the lppProblems parameter. When CopyProps returns S_OK, check for possible errors with individual properties in the structure. When CopyProps returns an error, no information is returned in the SPropProblemArray structure. Instead, call IMAPIProp::GetLastError to retrieve detailed error information.

If CopyProps returns S_OK, free the returned SPropProblemArray structure by calling the MAPIFreeBuffer function.

If you are copying properties that are unique to the source object type, you must be sure that the destination object is of the same type. CopyProps does not prevent you from associating properties that typically belong to one type of object with another type of object. It is up to you to copy properties that make sense for the destination object. For example, you should not copy message properties to an address book container.

To ensure that you are copying between objects of the same type, check that the source and destination object are the same type, either by comparing object pointers or calling IUnknown::QueryInterface. Set the interface identifier pointed to by lpInterface to the standard interface for the source object. Also, make sure that the object type — or PR_OBJECT_TYPE property — is the same for the two objects. For example, if you are copying from a message, set lpInterface to IID_IMessage and the PR_OBJECT_TYPE for both objects to MAPI_MESSAGE.

If an invalid pointer is passed in the lpDestObj parameter, the results are unpredictable.

To copy a message's recipient list, call the message's IMAPIProp::CopyProps method and include the PR_MESSAGE_RECIPIENTS property in the property tag array. To copy the message's attachments, include the PR_MESSAGE_ATTACHMENTS property.

To copy a folder or address book container's hierarchy or contents table, include PR_CONTAINER_HIERARCHY or PR_CONTAINER_CONTENTS in the property tag array. To include a folder's associated contents table, include the PR_FOLDER_ASSOCIATED_CONTENTS property in the array.

See Also

IMAPIFolder::CopyMessages, IMAPIProp::CopyTo, IMAPIProp::GetLastError, SPropProblemArray, SPropTagArray


IMAPIProp::CopyTo

The IMAPIProp::CopyTo method copies or moves all properties, except for specifically excluded properties.

Quick Info

See IMAPIProp : IUnknown.

HRESULT CopyTo(
  ULONG ciidExclude,
  LPCIID rgiidExclude,
  LPSPropTagArray lpExcludeProps,
  ULONG ulUIParam,
  LPMAPIPROGRESS lpProgress,
  LPCIID lpInterface,
  LPVOID lpDestObj,
  ULONG ulFlags,
  LPSPropProblemArray FAR * lppProblems
);

Parameters

ciidExclude
[in] Count of interfaces to exclude when copying or moving properties.
rgiidExclude
[in] Array of interface identifiers (IIDs) indicating interfaces that should not be used when copying or moving supplemental information to the destination object.
lpExcludeProps
[in] Pointer to a property tag array identifying the property tags that should be excluded from the copy or move operation. Passing NULL in the lpExcludeProps parameter indicates that all of the object's properties should be copied or moved. CopyTo returns MAPI_E_INVALID_PARAMETER when the cValues member of the SPropTagArray structure pointed to by lpExcludeProps is set to zero.
ulUIParam
[in] Handle of the parent window for the progress indicator.
lpProgress
[in] Pointer to a progress indicator implementation. If NULL is passed in the lpProgress parameter, MAPI provides the progress implementation. The lpProgress parameter is ignored unless the MAPI_DIALOG flag is set in the ulFlags parameter.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the object pointed to by lpDestObj. The lpInterface parameter must not be NULL.
lpDestObj
[in] Pointer to the object to receive the copied or moved properties.
ulFlags
[in] Bitmask of flags that controls the copy or move operation. The following flags can be set:
MAPI_DECLINE_OK
If CopyTo calls the IMAPISupport::DoCopyTo method to handle the copy or move operation, it should instead return immediately with the error value MAPI_E_DECLINE_COPY. The MAPI_DECLINE_OK flag is set by MAPI to limit recursion. Clients do not set this flag.
MAPI_DIALOG
Allows the display of a progress indicator.
MAPI_MOVE
CopyTo should perform a move operation rather than a copy operation. When this flag is not set, CopyTo performs a copy operation.
MAPI_NOREPLACE
Existing properties in the destination object should not be overwritten. When this flag is not set, CopyTo overwrites existing properties.
lppProblems
[in, out] On input, can be NULL, indicating no need for error information, or a pointer to a pointer to an SPropProblemArray structure. If lppProblems is a valid pointer on input, CopyTo returns detailed information about errors in copying one or more properties.

Return Values

S_OK
The properties have been successfully copied or moved.
MAPI_E_COLLISION
A subobject cannot be copied because there is already an subobject existing in the destination object with the same display name (PR_DISPLAY_NAME property) as the subobject to be copied.
MAPI_E_DECLINE_COPY
The service provider does not implement the copy operation.
MAPI_E_FOLDER_CYCLE
The source object performing the copy or move operation directly or indirectly contains the destination object. Significant work might have been performed before this condition was discovered, so the source and destination objects might be partially modified.
MAPI_E_INTERFACE_NOT_SUPPORTED
The interface identified by the lpInterface parameter is not supported by the destination object.
MAPI_E_NO_ACCESS
An attempt was made to access an object for which the caller has insufficient permissions. This error is returned if the destination object is the same as the source object.

The following values can be returned in the SPropProblemArray structure, but not as return values for CopyTo. These errors apply to a single property:

MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and CopyTo does not support Unicode, or MAPI_UNICODE was not set and CopyTo only supports Unicode.
MAPI_E_COMPUTED
The property cannot be modified by the caller because it is a read-only property, computed by the owner of the destination object. This error is not severe; the caller should allow the copy operation to continue.
MAPI_E_INVALID_TYPE
The property type is invalid.
MAPI_E_UNEXPECTED_TYPE
The property type is not the type expected by the caller.

Remarks

The IMAPIProp::CopyTo method by default copies or moves all of the current object's properties to a destination object. CopyTo is used when an object should be copied or moved exactly, with all or most of its properties intact.

Any subobjects in the source object are automatically included in the operation and copied or moved in their entirety. By default, CopyTo overwrites any properties in the destination object that match properties from the source object. If any of the copied or moved properties already exist in the destination object, the existing properties are overwritten by the new, unless the MAPI_NOREPLACE flag is set in the ulFlags parameter. Existing information in the destination object that is not overwritten is left untouched.

Notes to Implementers

You can provide a full implementation of CopyTo or rely on the implementation that MAPI provides in its support object. If you want to use the MAPI implementation, call IMAPISupport::DoCopyTo. However, If you do delegate processing to DoCopyTo and you are passed the MAPI_DECLINE_OK flag, avoid the support call and return MAPI_E_DECLINE_COPY instead. You will be called with this flag by MAPI to avoid the possible recursion that can happen when copying folders.

Because the copy operation can be lengthy, you are encouraged to display a progress indicator. Use the IMAPIProgress implementation passed in the lpProgress parameter, if there is one. If lpProgress is NULL, call IMAPISupport::DoProgressDialog to use the MAPI implementation.

Do not attempt to set any known read-only properties in the destination object; return MAPI_E_NO_ACCESS instead.

The source and destination objects should use the same interfaces. Return MAPI_E_INVALID_PARAMETER if lpInterface is not set.

Return MAPI_E_INTERFACE_NOT_SUPPORTED if all known interfaces are excluded.

Notes to Callers

Do not set the MAPI_DECLINE_OK flag; it is used by MAPI in its calls to message store provider CopyTo implementations.

Because copy and move operations can take time, it is wise to request the display of a progress indicator by setting the MAPI_DIALOG flag. You can set the lpProgress parameter to your implementation of IMAPIProgress, if you have one, or to NULL. If lpProgress is NULL, CopyTo will use the default progress indicator provided by MAPI.

You can suppress the display of a progress indicator by not setting the MAPI_DIALOG flag. CopyTo will ignore the ulUIParam and lpProgress parameters and avoid displaying the indicator.

CopyTo can report global and individual errors, or errors that occur with one or more properties. These individual errors are placed in an SPropProblemArray structure. You can suppress error reporting at the property level by passing NULL for the property problem array structure parameter rather than a valid pointer.

If you want to receive information about errors, pass a valid SPropProblemArray structure pointer in the lppProblems parameter. When CopyTo returns S_OK, check for possible errors with individual properties in the structure. When CopyTo returns an error, no information is returned in the SPropProblemArray structure. Instead, call IMAPIProp::GetLastError to retrieve detailed error information.

If CopyTo returns S_OK, free the returned SPropProblemArray structure by calling the MAPIFreeBuffer function.

If you are copying properties that are unique to the source object type, you must be sure that the destination object is of the same type. CopyTo does not prevent you from associating properties that typically belong to one type of object with another type of object. It is up to you to copy properties that make sense for the destination object. For example, you should not copy message properties to an address book container.

To ensure that you are copying between objects of the same type, check that the source and destination object are the same type, either by comparing object pointers or calling IUnknown::QueryInterface. Set the interface identifier pointed to by lpInterface to the standard interface for the source object. Also, make sure that the object type — or PR_OBJECT_TYPE property — is the same for the two objects. For example, if you are copying from a message, set lpInterface to IID_IMessage and the PR_OBJECT_TYPE for both objects to MAPI_MESSAGE.

If an invalid pointer is passed in the lpDestObj parameter, the results are unpredictable.

Excluding properties on a CopyTo call can be useful. For example, some objects have properties that are specific to a single instance of the object, such as the date and time of message delivery. To avoid copying a message's delivery time when copying the message to a different folder, specify PR_MESSAGE_DELIVERY_TIME in the property tag exclude array. To exclude a message's recipient list, add the PR_MESSAGE_RECIPIENTS property to the exclude array. To exclude a message's attachments, add the PR_MESSAGE_ATTACHMENTS property to the array.

Similarly, prevent the copying or moving of a folder or address book container's hierarchy or contents table by including PR_CONTAINER_HIERARCHY or PR_CONTAINER_CONTENTS in the property tag exclude array.

To exclude properties from the copy or move operation, include their property tags in the lpExcludeProps parameter. If you pass the results of using the PROP_TAG macro to build a property tag from a specific identifier in the property tag array, all properties with that identifier will be excluded. For example, the following entry in the property tag array causes all properties with an identifier of 0x8002 to be excluded, regardless of type:

PROP_TAG(PT_LONG, 0x8002)

The PR_NULL property tag cannot be included in the lpExcludeProps array.

The usefulness of the CopyTo feature for excluding interfaces is perhaps not as obvious as the usefulness of excluding properties. You can exclude an interface when copying to an object that has no knowledge of a group of properties. For example, if you are copying properties from a folder to an attachment, the only properties that the attachment will be able to work with are the generic properties accessible with any IMAPIProp implementation. By excluding IMAPIFolder from the copy operation, the attachment will not receive any of the more specific folder properties.

When you use the rgiidExclude parameter to exclude an interface, it also excludes all interfaces derived from that interface. For example, excluding IMAPIContainer causes folders or address book containers to be excluded, depending on the type of provider. Do not exclude IMAPIProp or IUnknown because so many interfaces derive from them.

Ignore MAPI_E_COMPUTED errors returned in the SPropProblemArray structure in the lppProblems parameter.

See Also

IMAPIFolder::CopyMessages, IMAPIProp::GetLastError, SPropProblemArray, SPropTagArray


IMAPIProp::DeleteProps

The IMAPIProp::DeleteProps method deletes one or more properties.

Quick Info

See IMAPIProp : IUnknown.

HRESULT DeleteProps(
  LPSPropTagArray lpPropTagArray,
  LPSPropProblemArray FAR * lppProblems
);

Parameters

lpPropTagArray
[in] Pointer to an array of property tags indicating the properties to delete. The cValues member of the SPropTagArray structure pointed to by lpPropTagArray must not be zero and the lpPropTagArray parameter itself must not be NULL.
lppProblems
[in, out] On input, can be NULL, indicating no need for error information, or a pointer to a pointer to an SPropProblemArray structure. If lppProblems is a valid pointer on input, DeleteProps returns detailed information about errors in deleting one or more properties.

Return Values

S_OK
Properties were successfully deleted.
MAPI_E_NO_ACCESS
The caller has insufficient permissions to delete properties.

Remarks

The IMAPIProps::DeleteProps method removes one or more properties from the current object.

Notes to Implementers

You do not have to allow properties to be deleted from all objects. If the object is not modifiable, return MAPI_E_NO_ACCESS from DeleteProps.

Notes to Callers

You do not need to set the property type for each property tag in the property tag array pointed to by lpPropTagArray. Property types are ignored; only the property identifiers are used.

Be aware that some objects do not allow modification and that these objects return MAPI_E_NO_ACCESS from DeleteProps. Other objects allow some properties to be deleted, but not others. When there is a problem deleting only some of the properties, DeleteProps returns S_OK. If you have passed a valid pointer in the lppProblems parameter, DeleteProps will set it to an SPropProblemArray structure containing detailed information about the problems with each of the properties. For example, if you are deleting all of the properties of a message and there is a problem with one or more of its attachments, the SPropProblemArray structure will contain an entry for PR_MESSAGE_ATTACHMENTS.

The structure pointed to by lppProblems is only valid if DeleteProps returns S_OK. If DeleteProps returns an error, do not attempt to use the SPropProblemArray structure. Instead, call the object's IMAPIProp::GetLastError method to get more information about the error.

Free the returned SPropProblemArray structure by calling the MAPIFreeBuffer function.

See Also

IMAPIProp::GetProps, IMAPIProp::SaveChanges, MAPIFreeBuffer, SPropTagArray


IMAPIProp::GetIDsFromNames

The IMAPIProp::GetIDsFromNames method provides the property identifiers that correspond to one or more property names.

Quick Info

See IMAPIProp : IUnknown.

HRESULT GetIDsFromNames(
  ULONG cPropNames,
  LPMAPINAMEID FAR * lppPropNames,
  ULONG ulFlags,
  LPSPropTagArray FAR * lppPropTags
);

Parameters

cPropNames
[in] Count of property names pointed to by the lppPropNames parameter. If lppPropNames is NULL, the cPropNames parameter must be zero.
lppPropNames
[in] Pointer to an array of property names or NULL. Passing NULL requests property identifiers for all property names in all property sets about which the object has information. The lppPropNames parameter must not be NULL if the MAPI_CREATE flag is set in the ulFlags parameter.
ulFlags
[in] Bitmask of flags that indicates how the property identifiers should be returned. The following flag can be set:
MAPI_CREATE
Assigns a property identifier to one or more of the names included in the property name array pointed to by lppPropNames if one has not yet been assigned. Internally registers the identifier in the name-to-identifier mapping table.
lppPropTags
[out] Pointer to a pointer to an array of property tags containing existing or newly assigned property identifiers. The property types for the property tags in this array are set to PT_UNSPECIFIED.

Return Values

S_OK
The identifiers for the specified property names were successfully returned.
MAPI_E_NO_SUPPORT
The object does not support named properties.
MAPI_E_NOT_ENOUGH_MEMORY
Insufficient memory was available to retrieve the identifiers.
MAPI_E_TOO_BIG
The operation cannot be performed because it requires too many property tags be returned.
MAPI_W_ERRORS_RETURNED
The call succeeded overall, but one or more property identifiers could not be returned. The corresponding property type for each inaccessible property is set to PT_ERROR and its identifier to zero. When this warning is returned, handle the call as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IMAPIProp::GetIDsFromNames method retrieves an array of property tags that hold the property identifiers for one or more named properties. IMAPIProp::GetIDsFromNames can be called to:

  • Create identifiers for new names.
  • Retrieve identifiers for specific names.
  • Retrieve identifiers for all named properties that are included in the object's mapping.

Named properties are commonly used by message store providers for folders and messages. Other objects, such as messaging users and profile sections, might not support the association of names to property identifiers and return MAPI_E_NO_SUPPORT from GetIDsFromNames.

If there is an error returning an identifier for a particular name, GetIDsFromNames returns MAPI_W_ERRORS_RETURNED and sets the property type in the property tag array entry that corresponds to the name to PT_ERROR and the identifier to zero.

Name-to-identifier mapping is represented by an object's PR_MAPPING_SIGNATURE property. PR_MAPPING_SIGNATURE contains a MAPIUID structure that indicates the service provider responsible for the object. If the PR_MAPPING_SIGNATURE property is the same for two objects, assume that these objects use the same name-to-identifier mapping.

Notes to Implementers

The identifiers that you pass back in the property tag array pointed to by lppPropNames must be in the 0x8000 to 0xFFFE range. The entries in this array must be in the same order as the names passed in the property name array pointed to by lppPropNames.

If you support named properties on a container, use the same name-to-identifier mapping for all objects in your container. That is, do not use a different mapping for each folder in your message store or each message in your folder.

Notes to Callers

Because the property types for the returned identifiers in the property tag array pointed to by lppPropTags are set to PT_UNSPECIFIED, you will need to call IMAPIProp::SetProps to retrieve the accurate types.

If you move or copy objects with named properties, and the source and destination objects have different mapping signatures as indicated by the values of their PR_MAPPING_SIGNATURE properties, you must preserve the names during these operations. To preserve property names, adjust the corresponding property identifiers to match the name-to-identifier mapping of the destination object.

Some objects have a limit as to the number of property identifiers they can name. If a call to GetIDsFromNames causes this limit to be exceeded, the method returns MAPI_E_TOO_BIG. In this case, query by identifier.

For more information, see Named Properties.

See Also

IMAPIProp::GetNamesFromIDs, MAPINAMEID, MAPIUID


IMAPIProp::GetLastError

The IMAPIProp::GetLastError method returns a MAPIERROR structure containing information about the previous error.

Quick Info

See IMAPIProp : IUnknown.

HRESULT GetLastError(
  HRESULT hResult,
  ULONG ulFlags,
  LPMAPIERROR FAR * lppMAPIError
);

Parameters

hResult
[in] HRESULT data type containing the error code generated in the previous method call.
ulFlags
[in] Bitmask of flags that indicates the format for the text returned in the MAPIERROR structure pointed to by lppMAPIError. The following flag can be set:
MAPI_UNICODE
The strings should be in Unicode format. If the MAPI_UNICODE flag is not set, the strings should be in ANSI format.
lppMAPIError
[out] Pointer to a pointer to the MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no error information to return.

Return Values

S_OK
The error information was returned.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Remarks

The IMAPIProp::GetLastError method supplies information about a prior method call that failed. Clients can provide their users with detailed information about the error by including the data from the MAPIERROR structure in a dialog box.

All of the implementations of GetLastError provided by MAPI are ANSI implementations except for the IAddrBook implementation. The GetLastError method included with IAddrBook supports Unicode on Windows NT platforms only.

Notes to Implementers

The specifics of a remote transport provider's implementation of this method and what messages this method returns are up to the transport provider, since the particular error conditions which lead to various HRESULT values will be different for different transport providers.

Notes to Callers

You can make use of the MAPIERROR structure pointed to by the lppMAPIError parameter, if GetLastError supplies one, only if the return value is S_OK. Sometimes GetLastError cannot determine what the last error was or has nothing more to report about the error. In this situation, a pointer to NULL is returned in lppMAPIError instead.

To release the memory for the MAPIERROR structure, call MAPIFreeBuffer.

For more information about the GetLastError method, see Using Extended Errors.

See Also

MAPIERROR, MAPIFreeBuffer


IMAPIProp::GetNamesFromIDs

The IMAPIProp::GetNamesFromIDs method provides the property names that correspond to one or more property identifiers.

Quick Info

See IMAPIProp : IUnknown.

HRESULT GetNamesFromIDs(
  LPSPropTagArray FAR * lppPropTags,
  LPGUID lpPropSetGuid,
  ULONG ulFlags,
  ULONG FAR * lpcPropNames,
  LPMAPINAMEID FAR * FAR * lpppPropNames
);

Parameters

lppPropTags
[in, out] On input, can be NULL, indicating that all names should be returned; or can be a pointer to an SPropTagArray structure containing an array of property tags. The cValues member for the property tag array cannot be zero. If lppPropTags is a valid pointer on input, GetNamesFromIDs returns names for each of the property identifiers included in the array.
lpPropSetGuid
[in] Pointer to a globally unique identifier, or GUID structure, identifying a property set. The lpPropSetGuid parameter can point to a valid property set or contain NULL.
ulFlags
[in] Bitmask of flags that indicates the type of names to be returned. The following flags can be used:
MAPI_NO_IDS
Requests that only names stored as Unicode strings be returned.
MAPI_NO_STRINGS
Requests that only names stored as numeric identifiers be returned.

If both flags are set, no names will be returned.

lpcPropNames
[out] Pointer to a count of the property name pointers in the array pointed to by lpppPropNames.
lpppPropNames
[out] Pointer to an array of pointers to MAPINAMEID structures containing property names.

Return Values

S_OK
The property names were successfully returned.
MAPI_E_NO_SUPPORT
The object does not support named properties.
MAPI_W_ERRORS_RETURNED
The call succeeded overall, but names for one or more properties could not be returned. The property tags for the failing properties have a property type of PT_ERROR. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.
MAPI_E_INVALID_PARAMETER
The cValues member of one or more of the entries in the property tag array pointed to by lppPropTags is set to zero.

Remarks

While access to most properties is by property identifier, some properties can be accessed by name. The IMAPIProp::GetNamesFromIDs method can be called to:

  • Retrieve names for specific property identifiers in a specific property set.
  • Retrieve names for specific property identifiers in any property set.
  • Retrieve names for all named properties that are included in the object's mapping.

If lppPropTags points to a valid property tag array with one or more property identifiers and lpPropSetGuid points to a valid property set, GetNamesFromIDs ignores the property set and the property types and returns all of the names that map to the specified identifiers.

If lppPropTags points to a valid property tag array with one or more property identifiers and lpPropSetGuid is NULL, GetNamesFromIDs returns all of the names that map to the specified identifiers.

If a specified identifier does not have a name, GetNamesFromIDs returns NULL in that identifier's place in the structure returned in lpppPropNames and also returns MAPI_W_ERRORS_RETURNED.

If both lpPropSetGuid and lppPropTags are NULL, GetNamesFromIDs allocates a new property tag array and returns all of the names for all of the named properties for the object.

When there are no names to be returned, perhaps because there are no properties in the requested property set or all of the properties are of a type excluded by the flags, GetNamesFromIDs:

  • Returns S_OK.
  • Allocates a new SPropTagArray structure, setting the cValues member to 0.
  • Sets the contents of lpcPropNames to zero.
  • Sets the contents of lpppPropNames to NULL.

Notes to Implementers

If lpPropSetGuid points to a valid property set and lppPropsTags is NULL, the result is undefined. You can implement one of the following strategies:

  • Ignore the property set and return the names for the identifiers in the property tag array.
  • Return the names for only the identifiers in the property tag array that belong to the specified property set.
  • Fail the call, returning MAPI_E_INVALID_PARAMETER.

Notes to Callers

To retrieve all of the named properties for an object, you must first call the object's IMAPIProp::GetPropList method and then pass the returned identifiers that are above the 0x8000 range to GetNamesFromIDs.

If you pass a valid property set but not a valid property tag array, be prepared for unpredictable results. Some implementations of GetNamesFromIDs ignore the property set and return the names for the identifiers in the property tag array. Some implementations return MAPI_E_INVALID_PARAMETER. Still other implementations return names for identifiers of all properties in the property set. If the property set is PS_PUBLIC_STRINGS, GetNamesFromIDs can return all names that were ever created. Whether or not the service provider stores a property under the identifiers associated with the public strings is immaterial.

When you are finished with the property names, check the contents of the lpcPropNames parameter to determine if any names were returned. If so, call MAPIFreeBuffer to free the memory pointed to by lppPropTags and lpppPropNames when success is returned. One call to MAPIFreeBuffer is sufficient for each parameter; you do not need to traverse the array of pointers and free each MAPINAMEID structure individually.

For more information about named properties, see Named Properties.

See Also

IMAPIProp::GetIDsFromNames


IMAPIProp::GetPropList

The IMAPIProp::GetPropList method returns property tags for all properties.

Quick Info

See IMAPIProp : IUnknown.

HRESULT GetPropList(
  ULONG ulFlags,
  LPSPropTagArray FAR * lppPropTagArray
);

Parameters

ulFlags
[in] Bitmask of flags that controls the format for the strings in the returned property tags. The following flag can be set:
MAPI_UNICODE
The returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppPropTagArray
[out] Pointer to a pointer to the property tag array containing tags for all of the object's properties.

Return Values

S_OK
All of the property tags were returned successfully.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Remarks

The IMAPIProp::GetPropList method retrieves the property tag for each property currently supported by an object. If the object does not currently support any properties, GetPropList returns a property tag array with the cValues member set to zero.

The scope of properties returned by GetPropList varies from provider to provider. Some service providers exclude those properties for which the caller does not have access. All providers return properties of type PT_OBJECT.

If the object does not support Unicode, GetPropList returns MAPI_E_BAD_CHARWIDTH, even if there are no string properties defined for the object.

Notes to Implementers

Remote transport providers implement GetPropList exactly as specified here. There are no special concerns. Your implementation should, of course, return the same list of properties as supported by the GetProps method.

Notes to Callers

Call the MAPIFreeBuffer function to free the property tag array pointed to by lppPropTagArray.

See Also

MAPIFreeBuffer


IMAPIProp::GetProps

The IMAPIProp::GetProps method retrieves the property value of one or more properties of an object.

Quick Info

See IMAPIProp : IUnknown.

HRESULT GetProps(
  LPSPropTagArray lpPropTagArray,
  ULONG ulFlags,
  ULONG FAR * lpcValues,
  LPSPropValue FAR * lppPropArray
);

Parameters

lpPropTagArray
[in] Pointer to an array of property tags identifying the properties whose values are to be retrieved. The lpPropTagArray parameter must either be NULL, indicating that values for all properties of the object should be returned, or point to an SPropTagArray structure containing one or more property tags.
ulFlags
[in] Bitmask of flags that indicates the format for properties that have the type PT_UNSPECIFIED. The following flag can be set:
MAPI_UNICODE
The string values for these properties should be returned in the Unicode format. If the MAPI_UNICODE flag is not set, the string values should be returned in the ANSI format.
lpcValues
[out] Pointer to a count of property values pointed to by the lppPropArray parameter. If lppPropArray is NULL, the contents of the lpcValues parameter is zero.
lppPropArray
[out] Pointer to a pointer to the retrieved property values.

Return Values

S_OK
The property values were successfully retrieved.
MAPI_W_ERRORS_RETURNED
The call succeeded overall, but one or more properties could not be accessed. The ulPropTag member of the property value for each unaccessible property has a property type of PT_ERROR and an identifier of zero. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.
MAPI_E_INVALID_PARAMETER
Zero was passed in the cValues member of the SPropTagArray structure pointed to by lpPropTagArray.

Remarks

The IMAPIProp::GetProps method gets the property values of one or more properties of an object.

The property values are returned in the same order as they were requested. That is, the order of properties in the property tag array pointed to by lpPropTagArray matches the order in the array of property value structures pointed to by lppPropArray.

The property types specified in the aulPropTag members of the property tag array indicate the type of value that should be returned in the Value member of each property value structure. However, if the caller does not know the type of a property, the type in the aulPropTag member can be set instead to PT_UNSPECIFIED. In retrieving the value, GetProps sets the correct type in the ulPropTag member of the property value structure for the property.

If property types are specified in the SPropTagArray in lpPropTagArray, then the property values in the SPropValue returned in lppPropArray have types that exactly match the requested types, unless an error value is returned instead.

String properties can have one of two property types: PT_UNICODE to represent the Unicode format and PT_STRING8 to represent the ANSI format. If the MAPI_UNICODE flag is set in the ulFlags parameter, whenever GetProps cannot determine the appropriate format for a string property, it returns its value in the Unicode format. GetProps cannot determine an exact string property type:

  • If the lpPropTagArray parameter is set to NULL to request all properties.
  • When the aulPropTag member includes the value PT_UNSPECIFIED as its property type in the property tag array.

If the lpPropTagArray parameter is set to NULL to retrieve all of the properties of the object and no properties exist, GetProps:

  • Returns S_OK.
  • Sets the count value in the cValues member of the property value structure to zero.
  • Sets the contents of lpcValues to zero.
  • Sets lppPropArray to NULL.
  • Must not return multivalued properties with cValues set to zero.

Notes to Implementers

Call the MAPIAllocateBuffer function to allocate memory initially for the SPropValue structure pointed to by lpPropTagArray; call MAPIAllocateMore to allocate any additional memory needed for the structure's members.

Return MAPI_W_ERRORS_RETURNED if you cannot retrieve the value for one or more of the requested properties. In the property value structure, set the type in the ulPropTag member to PT_ERROR and the Value member to a status code describing the error. For example, if you need to convert a string to Unicode and do not support Unicode, set the Value member to MAPI_E_BAD_CHARWIDTH. If the property is too large, set it to MAPI_E_NOT_ENOUGH_MEMORY. If the object does not support the property, set it to MAPI_E_NOT_FOUND.

A remote transport provider's implementation of the GetProps method must return the folder's property values for properties requested by the caller. Your implementation needs to:

  • Allocate a property value array to return to the caller and store its address in the property value pointer parameter passed in for that purpose.
  • Copy the property tags from the folder's properties into the property tags in the property value array according to the array of property tags passed to GetProps.
  • Ensure that the property type is set for all property tags passed to GetProps. The caller can pass in a property type of PT_UNSPECIFIED, in which case GetProps must set the correct property type for that property tag.
  • Set the value of each property in the property value array according to its tag. For example, if the property tag requested by the caller is PR_OBJECT_TYPE, GetProps can set the value to MAPI_FOLDER.
  • If the caller passes in any property tags that your implementation does not handle, you can set the property tag to PT_ERROR for those properties, and set the property value to MAPI_E_NOT_FOUND.
  • Return S_OK if no errors occurred or MAPI_W_ERRORS_RETURNED if there were errors.

A remote transport provider's implementation of the GetProps method needs to support the following properties at a minimum:

PR_ACCESS | PR_ACCESS_LEVEL
PR_CONTENT_COUNT | PR_ASSOC_CONTENT_COUNT
PR_FOLDER_TYPE | PR_OBJECT_TYPE
PR_SUBFOLDERS | PR_CREATION_VERSION
PR_CREATION_TIME | PR_DISPLAY_NAME
PR_DISPLAY_TYPE |

Notes to Callers

For properties of type PT_OBJECT, call the IMAPIProp::OpenProperty method instead of GetProps.

For secure properties, do not expect to retrieve them by calling GetProps with the lppPropTagArray parameter set to NULL. You must explicitly set a secure property's identifier in the aulPropTag member of its property tag array when calling GetProps. When and how a secure property is available is up to the service provider.

Free the returned SPropValue structure by calling the MAPIFreeBuffer function only if GetProps returns S_OK or MAPI_W_ERRORS_RETURNED.

If GetProps returns MAPI_W_ERRORS_RETURNED because it could not access one or more properties, check the property tags of the returned properties. The failed properties will have the following values set in their property value structure:

  • Property type in the ulPropTag member set to PT_ERROR.
  • Property value in the Value member set to a status code for the error, such as MAPI_E_NOT_FOUND.

Properties that fail because they are too large to conveniently be returned in the property value structure have their Value member set to MAPI_E_NOT_ENOUGH_MEMORY. Typically, this occurs with string or binary properties of type PT_STRING8, PT_UNICODE, or PT_BINARY when the value of the property is 4K or larger. Call IMAPIProp::OpenProperty to retrieve large properties.

Not all implementations of GetProps support both the Unicode and ANSI formats for character strings. When a particular property requires string format conversion and GetProps cannot support it, the Value member for the property is set to MAPI_E_BAD_CHARWIDTH.

For more information about using GetProps to access properties, see Retrieving Properties.

See Also

IMAPIProp::OpenProperty, MAPIAllocateBuffer, MAPIAllocateMore, MAPIFreeBuffer, SPropTagArray, SPropValue


IMAPIProp::OpenProperty

The IMAPIProp::OpenProperty method returns a pointer to an interface to be used to access a property.

Quick Info

See IMAPIProp : IUnknown.

HRESULT OpenProperty(
  ULONG ulPropTag,
  LPCIID lpiid,
  ULONG ulInterfaceOptions,
  ULONG ulFlags,
  LPUNKNOWN FAR * lppUnk
);

Parameters

ulPropTag
[in] Property tag for the property to be accessed. Both the identifier and the type must be included in the property tag.
lpiid
[in] Pointer to the identifier for the interface to be used to access the property. The lpiid parameter must not be NULL.
ulInterfaceOptions
[in] Data that relates to the interface identified by the lpiid parameter.
ulFlags
[in] Bitmask of flags that controls access to the property. The following flags can be set:
MAPI_CREATE
If the property does not exist, it should be created. If the property does exist, the current value of the property should be discarded. When a caller sets the MAPI_CREATE flag, it should also set the MAPI_MODIFY flag.
MAPI_DEFERRED_ERRORS
Allows OpenProperty to return successfully, possibly before the object is fully accessible to the caller. If the object is not accessible, making a subsequent object call can result in an error.
MAPI_MODIFY
Requests read/write access to the property. The default access is read-only. MAPI_MODIFY must be set when MAPI_CREATE is set.
lppUnk
[out] Pointer to the requested interface to be used for property access.

Return Values

S_OK
The requested interface pointer was successfully returned.
MAPI_E_INTERFACE_NOT_SUPPORTED
The requested interface is not supported for this property.
MAPI_E_NO_ACCESS
The caller has insufficient permissions to access the property.
MAPI_E_NO_SUPPORT
The object cannot provide access to this property through the requested interface.
MAPI_E_NOT_FOUND
The requested property does not exist and MAPI_CREATE was not set in the ulFlags parameter.
MAPI_E_INVALID_PARAMETER
The property type in the tag is set to PT_UNSPECIFIED.

Remarks

The IMAPIProp::OpenProperty method provides access to a property through a particular interface. OpenProperty is an alternate to GetProps and SetProps. When either GetProps or SetProps fails because the property is too large or too complex, call OpenProperty. OpenProperty is commonly used to access properties of type PT_OBJECT.

Notes to Callers

To access message attachments, open the PR_ATTACH_DATA_OBJ property with a different interface identifier, depending on the type of attachment. The following table describes how to call OpenProperty for the different types of attachments:

Type of attachment | Interface identifier to use
Binary | IID_IStream
String | IID_IStream
Message | IID_IMessage
OLE 2 | IID_IStreamDocfile

IStreamDocfile is a derivative of IStream that is based on an OLE 2 compound file. IStreamDocfile is the best choice for accessing OLE 2 attachments because it involves the least amount of overhead. IID_IStreamDocFile can be used for those properties that contain data stored in structured storage accessible through the IStorage interface.

For more information about using OpenProperty with attachments, see PR_ATTACH_DATA_OBJ and Opening an Attachment.

Do not use the IStream pointer that you receive to call either its Seek or SetSize method unless you use a zero position or size variable. Also, do not rely on the value of the plibNewPosition output parameter returned from the Seek call.

If you call OpenProperty to access a property with the IStream interface, use only that interface to make changes to it. Do not attempt to update the property with any of the other IMAPIProp methods such as SetProps or DeleteProps.

Do not try to open a property with OpenProperty more than once. The results are undefined because they can vary from provider to provider.

If you need to modify the property to be opened, set the MAPI_MODIFY flag. If you are not sure if the object supports the property but think it should, set the MAPI_CREATE and MAPI_MODIFY flags. Whenever MAPI_CREATE is set, MAPI_MODIFY must also be set.

You are responsible for recasting the interface pointer returned in the lppUnk parameter to one appropriate for the interface specified in the lpiid parameter. You must also use the returned pointer to call its IUnknown::Release method when you have finished with it.

Sometimes setting the flags in the ulFlags parameter is not enough to indicate the type of access to the property that is required. You can place additional data such as flags in the ulInterfaceOptions parameter. This data is interface-dependent. Some interfaces, such as IStream, use it and others do not. For example, when opening a property to be modified with IStream, set the STGM_WRITE flag in the ulInterfaceOptions parameter in addition to MAPI_MODIFY. When opening a table using IMAPITable, you can set ulInterfaceOptions to MAPI_UNICODE to indicate whether or not the columns in the table that hold string properties should be in Unicode format.

See Also

HrIStorageFromStream, IMAPIProp::DeleteProps, IMAPIProp::GetProps, IMAPIProp::SetProps, IMAPISupport::IStorageFromStream


IMAPIProp::SaveChanges

The IMAPIProp::SaveChanges method makes permanent any changes made to an object since the last save operation.

Quick Info

See IMAPIProp : IUnknown.

HRESULT SaveChanges(
  ULONG ulFlags
);

Parameters

ulFlags
[in] Bitmask of flags that controls what happens to the object when the IMAPIProp::SaveChanges method is called.

The following flags can be set:

FORCE_SAVE
Changes should be written to the object, overriding any previous changes made to the object, and the object closed. Read/write access must have been set for the operation to succeed. The FORCE_SAVE flag is used after a previous call to SaveChanges returned MAPI_E_OBJECT_CHANGED.
KEEP_OPEN_READONLY
Changes should be committed and the object should be kept open for reading. No further changes will be made.
KEEP_OPEN_READWRITE
Changes should be committed and the object should be kept open for read/write access. This flag is usually set when the object was initially opened for read/write access. Subsequent changes to the object are allowed.
MAPI_DEFERRED_ERRORS
Allows SaveChanges to return successfully, possibly before the changes have been fully committed.

Return Values

S_OK
The commitment of changes has been successful.
MAPI_E_NO_ACCESS
SaveChanges cannot keep the object open for read-only access, if KEEP_OPEN_READONLY is set, or read/write access, if KEEP_OPEN_READWRITE is set. No changes are committed.
MAPI_E_OBJECT_CHANGED
The object has changed since it was opened.
MAPI_E_OBJECT_DELETED
The object has been deleted since it was opened.

Remarks

The IMAPIProp::SaveChanges method makes property changes permanent for objects that support the transaction model of processing, such as messages, attachments, address book containers, and messaging user objects. Objects that do not support transactions, such as folders, message stores, and profile sections, make changes permanent immediately. No call to SaveChanges is required.

Because service providers are not required to generate an entry identifier for their objects until all properties have been saved, an object's PR_ENTRYID property might not be available until after its SaveChanges method has been called. Some providers wait until the KEEP_OPEN_READONLY flag is set on the SaveChanges call. KEEP_OPEN_READONLY indicates that the changes to be saved in the current call will be the last changes that will be made on the object.

Some message store implementations do not show newly created messages in a folder until a client saves the message changes using SaveChanges and releases the message objects using the IUnknown::Release method. In addition, some object implementations cannot generate a PR_ENTRYID property for a newly created object until after SaveChanges has been called, and some can only do so after SaveChanges has been called with KEEP_OPEN_READONLY set in ulFlags.

Notes to Implementers

If you receive the KEEP_OPEN_READONLY flag, you have the option of leaving the object's access as read/write.

However, in no case can a provider leave an object in a read-only state when the KEEP_OPEN_READWRITE flag is passed.

When a client is saving multiple attachments to multiple messages, it will be calling the SaveChanges method for every attachment and every message. Often clients will set the MAPI_DEFERRED_ERRORS for each of these calls except for the last one. You can return errors either with the last call or earlier. You can even ignore the flag.

If either KEEP_OPEN_READWRITE or KEEP_OPEN_READONLY is set along with MAPI_DEFERRED_ERRORS, you can ignore the error deferment request. If MAPI_DEFERRED_ERRORS is not set in ulFlags, one of the previously deferred errors can be returned for the SaveChanges call.

Whether a remote transport provider provides a functional implementation of this method is optional and will probably depend on other design choices in your implementation. If you implement this method, do so according to the documentation here. Since folder objects and status objects are not transacted, at a minimum a remote transport provider's implementation of SaveChanges must return S_OK without actually doing any work.

Notes to Callers

If a client passes KEEP_OPEN_READONLY, then calls the IMAPIProp::SetProps method and then SaveChanges again, the same implementation might stop.

After receiving MAPI_E_NO_ACCESS from a call where you set KEEP_OPEN_READWRITE, you will continue to have read/write access to the object. You can call SaveChanges again, passing either the KEEP_OPEN_READONLY flag or no flags with the KEEP_OPEN_suffix.

Whether a provider supports the KEEP_OPEN_READWRITE flag depends on the provider's implementation.

To indicate that the only call to be made on the object after SaveChanges will be IUnknown::Release, set no flags for the ulFlags parameter. An error from SaveChanges indicates that it could not make the pending changes permanent. Different providers handle the absence of flags on the SaveChanges call differently. Some treat this state as the same as KEEP_OPEN_READONLY; others interpret it as the same as KEEP_OPEN_READWRITE. Still other providers shut down the object when they receive no flags on the SaveChanges call.

Some properties, typically computed properties, cannot be processed until you call SaveChanges and, in particular cases, Release.

When making bulk changes, such as saving attachments to multiple messages, defer error processing by setting the MAPI_DEFERRED_ERRORS flag in ulFlags. If you are saving multiple attachments to multiple messages, make one SaveChanges call to each attachment and one SaveChanges call to each message. Set the MAPI_DEFERRED_ERRORS flag for each attachment call and for all messages except for the last one.

If SaveChanges returns MAPI_E_OBJECT_CHANGED, check if the original object has been modified. If so, warn the user, who can either request that the changes overwrite the previous changes or save the object somewhere else. If the original object has been deleted, warn the user so that the user can be given the opportunity to save the object in an alternate location.

You cannot call SaveChanges with the FORCE_SAVE flag on an open object that has been deleted.

If SaveChanges returns an error, then the object whose changes were to be saved remains open, regardless of the flags set in the ulFlags parameter.

For more information, see Saving Properties.


IMAPIProp::SetProps

The IMAPIProp::SetProps method updates one or more properties.

Quick Info

See IMAPIProp : IUnknown.

HRESULT SetProps(
  ULONG cValues,
  LPSPropValue lpPropArray,
  LPSPropProblemArray FAR * lppProblems
);

Parameters

cValues
[in] Count of property values pointed to by the lpPropArray parameter. The cValues parameter must not be zero.
lpPropArray
[in] Pointer to an array of SPropValue structures holding property values to be updated.
lppProblems
[in, out] On input, can be NULL, indicating no need for error information, or a pointer to a pointer to an SPropProblemArray structure. If lppProblems is a valid pointer on input, SetProps returns detailed information about errors in updating one or more properties.

Return Values

S_OK
The properties were successfully updated.

The following values can be returned in the SPropProblemArray structure, but not as return values for SetProps:

MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.
MAPI_E_COMPUTED
The property cannot be updated because it is read-only, computed by the service provider responsible for the object.
MAPI_E_INVALID_TYPE
The property type is invalid.
MAPI_E_NO_ACCESS
An attempt was made to modify a read-only object or to access an object for which the user has insufficient permissions.
MAPI_E_NOT_ENOUGH_MEMORY
The property cannot be updated because it is larger than the RPC buffer size.
MAPI_E_UNEXPECTED_TYPE
The property type is not the type expected by the calling implementation.

Notes to Implementers

Ignore the PR_NULL property tag and all properties with a type of PT_ERROR; make no changes and report no problems in the SPropProblemArray structure.

Return MAPI_E_INVALID_PARAMETER if a property of type PT_OBJECT is included in the property value array. Also return this error if a multivalued property is included in the array and its cValues member is set to zero.

If the call succeeds overall but there are problems with setting some of the properties, return S_OK and place information about the problems in the appropriate entry of the SPropProblemArray structure pointed to by the lppProblems parameter.

Notes to Callers

Depending on the service provider, you might also be able to change the property type by passing a property tag containing a different type than was previously used with a given property identifier.

If you include a property tag for a property that is unsupported by the object and the implementation of SetProps allows the creation of new properties, the property is added to the object. Any previous value stored with the property identifier used for the new property is discarded.

Note that the S_OK return value does not guarantee that all of the properties were successfully updated. Some providers cache SetProps calls until they receive a call that requires provider intervention, such as IMAPIProp::SaveChanges or IMAPIProp::GetProps. Therefore, it is possible to receive error values relating to the SetProps call with the later calls.

If SetProps returns S_OK, check the SPropProblemArray structure pointed to by lppProblems for problems updating individual properties. If SetProps returns an error, do not check the property problem array. Instead, call the object's IMAPIProp::GetLastError method.

When updating large properties, SetProps can fail and return MAPI_E_NOT_ENOUGH_MEMORY. There is no maximum size for properties, and different objects can have different limits. If you deal with potentially large properties be prepared to call IMAPIProp::OpenProperty with IID_IStream as the interface identifier if SetProps returns this error value.

Call the MAPIFreeBuffer function to free the SPropProblemArray structure.

See Also

IMAPIProp::GetProps, IMAPIProp::SaveChanges, MAPIFreeBuffer, SPropProblemArray, SPropValue


IMAPISession : IUnknown

The IMAPISession interface is used to manage objects associated with a MAPI logon session.

Quick Info

Header file: | MAPIX.H
Exposed by: | Session objects
Implemented by: | MAPI
Called by: | Client applications and MAPI
Interface identifier: | IID_IMAPISession
Pointer type: | LPMAPISESSION

Vtable Order

GetLastError | Returns a MAPIERROR structure containing information about the previous session error.
GetMsgStoresTable | Provides access to the message store table — a table with information about all of the message stores in the session profile.
OpenMsgStore | Opens a message store and returns an IMsgStore pointer for further access.
OpenAddressBook | Opens the MAPI integrated address book and returns an IAddrBook pointer for further access.
OpenProfileSection | Opens a section of the current profile and returns an IProfSect pointer for further access.
GetStatusTable | Provides access to the status table — a table with information about all of the MAPI resources in the session.
OpenEntry | Opens an object and returns an interface pointer for further access.
CompareEntryIDs | Compares two entry identifiers to determine if they refer to the same object.
Advise | Registers to receive notification of specified events affecting the session.
Unadvise | Cancels the sending of notifications previously set up with a call to the IMAPISession::Advise method.
MessageOptions | Displays a dialog box showing option properties for a particular address type and message.
QueryDefaultMessageOpt | Retrieves the message option properties for a particular address type.
EnumAdrTypes | Returns the address types that can be handled by all of the transport providers in the session.
QueryIdentity | Returns the entry identifier of the object that provides the primary identity for the session.
Logoff | Ends a MAPI session.
SetDefaultStore | Establishes a message store as the default message store for the session.
AdminServices | Returns an IMsgServiceAdmin pointer for making changes to message services.
ShowForm | Displays a form.
PrepareForm | Creates a numeric token to be used by the IMAPISession::ShowForm method to access a message.


IMAPISession::AdminServices

The IMAPISession::AdminServices method returns an IMsgServiceAdmin pointer for making changes to message services.

Quick Info

See IMAPISession : IUnknown.

HRESULT AdminServices(
  ULONG ulFlags,
  LPSERVICEADMIN FAR * lppServiceAdmin
);

Parameters

ulFlags
Reserved; must be zero.
lppServiceAdmin
[out] Pointer to a pointer to a message service administration object.

Return Values

S_OK
A pointer to a message service administration object was successfully returned.

Notes to Callers

The IMAPISession::AdminServices method creates a message service administration object — an object that supports the IMsgServiceAdmin interface — and returns a pointer. With this pointer, you can call IMsgServiceAdmin methods to make changes to any of the message services in the session profile. Be aware that these changes do not take affect until the next session; the current session is unaffected.

See Also

IMsgServiceAdmin : IUnknown, IProfAdmin::AdminServices


IMAPISession::Advise

The IMAPISession::Advise method registers to receive notification of specified events affecting the session.

Quick Info

See IMAPISession : IUnknown.

HRESULT Advise(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  ULONG ulEventMask,
  LPMAPIADVISESINK lpAdviseSink,
  ULONG FAR * lpulConnection
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the address book or message store object about which notifications should be generated, or NULL, indicating that the client is registering to receive notifications about events that affect only the session.
ulEventMask
[in] A mask of values indicating the types of notification events that the client is interested in and should be included in the registration. If lpEntryID is NULL, MAPI automatically registers the client for critical error events for the session — the only type of event supported by the session.

When lpEntryID points to an entry identifier, the following values are valid for the ulEventMask parameter:

fnevCriticalError
Registers for notifications about severe errors, such as insufficient memory.
fnevExtended
Registers for notifications about events specific to a particular address book or message store provider and about session shut down.
fnevNewMail
Registers for notifications about the arrival of new messages.
fnevObjectCreated
Registers for notifications about the creation of a new object.
fnevObjectCopied
Registers for notifications about an object being copied.
fnevObjectDeleted
Registers for notifications about an object being deleted.
fnevObjectModified
Registers for notifications about an object being modified.
fnevObjectMoved
Registers for notifications about an object being moved.
fnevSearchComplete
Registers for notifications about the completion of a search operation.
lpAdviseSink
[in] Pointer to an advise sink object to receive the subsequent notifications. This advise sink object must have already been allocated.
lpulConnection
[out] Pointer to a nonzero number that represents the connection between the caller's advise sink object and the session.

Return Values

S_OK
The registration was successful.
MAPI_E_INVALID_ENTRYID
The entry identifier pointed to by lpEntryID does not represent a valid entry identifier.
MAPI_E_NO_SUPPORT
The service provider responsible for the entry identifier pointed to by lpEntryID either does not support the type of events specified in the ulEventMask parameter or does not support notification.
MAPI_E_UNKNOWN_ENTRYID
The entry identifier pointed to by lpEntryID cannot be handled by any of the service providers in the profile.

Remarks

The IMAPISession::Advise method establishes a connection between the caller's advise sink object, the session, and, as an option, a service provider. This connection is used to send notifications to the advise sink when one or more events as specified in the ulEventMask parameter occur to the object pointed to by lpEntryID. When lpEntryID is NULL, the target object is the session and notifications are sent for critical error and extended events only.

When lpEntryID points to a valid entry identifier, MAPI calls the Advise method of the logon object belonging to the responsible service provider. For example, if lpEntryID points to the entry identifier of a distribution list, MAPI calls the appropriate address book provider's IABLogon::Advise method.

To send a notification, either the service provider or MAPI calls the registered advise sink's IMAPIAdviseSink::OnNotify method. One of the parameters to OnNotify, a notification structure, contains information that describes the specific event.

Notes to Callers

On systems that support multiple threads of execution, the call to OnNotify can also occur on any thread at any time. If you must be assured that notifications only occur at a particular time on a particular thread, call HrThisThreadAdviseSink to generate the advise sink object that you pass to Advise.

To determine when a client has logged off, register for notifications in your service provider by calling Advise with lpEntryID set to NULL and cbEntryID set to zero. When the logoff occurs, you'll receive an fnevExtended notification.

After a call to Advise has succeeded and before Unadvise has been called to cancel the registration, be prepared for the advise sink object to be released. You should release your advise sink object after Advise returns unless you have a specific long-term use for it.

For an overview of the notification process, see Event Notification in MAPI.

For more information on handling notifications, see Handling Notifications.

See Also

NOTIFICATION, HrThisThreadAdviseSink, IMAPIAdviseSink::OnNotify, IMAPISession::Unadvise


IMAPISession::CompareEntryIDs

The IMAPISession::CompareEntryIDs method compares two entry identifiers to determine if they refer to the same object.

Quick Info

See IMAPISession : IUnknown.

HRESULT CompareEntryIDs(
  ULONG cbEntryID1,
  LPENTRYID lpEntryID1,
  ULONG cbEntryID2,
  LPENTRYID lpEntryID2,
  ULONG ulFlags,
  ULONG FAR * lpulResult
);

Parameters

cbEntryID1
[in] Count of bytes in the entry identifier pointed to by the lpEntryID1 parameter.
lpEntryID1
[in] Pointer to the first entry identifier to be compared.
cbEntryID2
[in] Count of bytes in the entry identifier pointed to by the lpEntryID2 parameter.
lpEntryID2
[in] Pointer to the second entry identifier to be compared.
ulFlags
Reserved; must be zero.
lpulResult
[out] Pointer to the result of the comparison, set toTRUE if the two entry identifiers refer to the same object and FALSE otherwise.

Return Values

S_OK
The comparison was successful.
MAPI_E_UNKNOWN_ENTRYID
One or both of the entry identifiers specified as parameters do not refer to objects, possibly because these objects are unopened and inaccessible at present.

Remarks

The IMAPISession::CompareEntryIDs method compares two entry identifiers belonging to a single service provider to determine whether they refer to the same object. MAPI extracts the MAPIUID portion from the entry identifiers to determine the service provider responsible for the objects and calls its logon object's CompareEntryIDs method to perform the comparison.

Notes to Callers

CompareEntryIDs is useful because an object can have more than one valid entry identifier; such a situation can occur, for example, after a new version of a service provider is installed.

If CompareEntryIDs returns an error, do not take any action based on the result of the comparison. Instead, take the most conservative approach possible. CompareEntryIDs might fail if, for example, one or both of the entry identifiers contains an invalid MAPIUID.


IMAPISession::EnumAdrTypes

The IMAPISession::EnumAdrTypes method returns the address types that can be handled by all of the transport providers in the session.

Quick Info

See IMAPISession : IUnknown.

HRESULT EnumAdrTypes(
  ULONG ulFlags,
  ULONG FAR * lpcAdrTypes,
  LPTSTR FAR * FAR * lpppszAdrTypes
);

Parameters

ulFlags
[in] Bitmask of flags that indicates the format for the returned address types. The following flag can be set:
MAPI_UNICODE
The address types are in Unicode format. If the MAPI_UNICODE flag is not set, the address types are in ANSI format.
lpcAdrTypes
[out] Pointer to a count of address types pointed to by the lpppszAdrTypes parameter.
lpppszAdrTypes
[out] Pointer to an array of pointers to address types.

Return Values

S_OK
The address types were successfully retrieved.

Remarks

The IMAPISession::EnumAdrTypes method returns a list of the address types that can be handled by all of the active transport providers in the session. The address types for transport providers that are not currently loaded are not included in the list. Transport providers register to handle one or more address types when MAPI calls their IXPLogon::AddressTypes method.

Notes to Callers

Call MAPIFreeBuffer to release the string array pointed to by the lpppszAdrTypes parameter.

See Also

MAPIFreeBuffer


IMAPISession::GetLastError

The IMAPISession::GetLastError method returns a MAPIERROR structure containing information about the previous session error.

Quick Info

See IMAPISession : IUnknown.

HRESULT GetLastError(
  HRESULT hResult,
  ULONG ulFlags,
  LPMAPIERROR FAR * lppMAPIError
);

Parameters

hResult
[in] HRESULT data type containing the error value generated in the previous method call.
ulFlags
[in] Bitmask of flags that controls the type of the returned strings. The following flag can be set:
MAPI_UNICODE
The strings in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppMAPIError
[out] Pointer to a pointer to a MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if MAPI cannot supply a MAPIERROR structure with appropriate information.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_BAD_CHARWIDTH
The MAPI_UNICODE flag was set and the session does not support Unicode.

Remarks

The IMAPISession::GetLastError method retrieves information about the last error that was returned by an IMAPISession method call. Clients can provide their users with detailed information about the error by including this information in a dialog box.

Notes to Callers

You can make use of the MAPIERROR structure pointed to by the lppMAPIError parameter, if MAPI supplies one, only if GetLastError returns S_OK. Sometimes MAPI cannot determine what the last error was or has nothing more to report about the error. In this situation, GetLastError returns a pointer to NULL in lppMAPIError instead.

For more information about the GetLastError method, see Using Extended Errors.

See Also

MAPIERROR, MAPIFreeBuffer


IMAPISession::GetMsgStoresTable

The IMAPISession::GetMsgStoresTable method provides access to the message store table — a table with information about all of the message stores in the session profile.

Quick Info

See IMAPISession : IUnknown.

HRESULT GetMsgStoresTable(
  ULONG ulFlags,
  LPMAPITABLE FAR * lppTable
);

Parameters

ulFlags
[in] Bitmask of flags that determines the format for columns that are character strings. The following flag can be set:
MAPI_UNICODE
The string columns are in Unicode format. If the MAPI_UNICODE flag is not set, the string columns are in ANSI format.
lppTable
[out] Pointer to a pointer to the message store table.

Return Values

S_OK
The table was successfully returned.
MAPI_E_BAD_CHARWIDTH
The MAPI_UNICODE flag was set and MAPI does not support Unicode at present.

Remarks

The IMAPISession::GetMsgStoresTable method retrieves a pointer to the message store table, a table maintained by MAPI that contains information about each open message store in the profile.

For a complete list of required and optional columns in the message store table, see Message Store Table.

Notes to Callers

Because MAPI updates the message store table during the session whenever changes occur, call the Advise method of the message store table to register to be notified of these changes. Possible changes include the addition of new message stores, removal of existing stores, and changes to the default store.

Setting the MAPI_UNICODE flag in the ulFlags parameter affects the format of the columns returned from the following IMAPITable methods:

  • IMAPITable::QueryColumns
  • IMAPITable::QueryRows

This flag also controls the property types in the sort order returned by the IMAPITable::QuerySortOrder method.

See Also

IMAPISession::openMsgStore, IMAPITable::QueryColumns, IMAPITable::QueryRows, IMAPITable::QuerySortOrder, IMAPITable::SetColumns, IMAPITable::SortTable


IMAPISession::GetStatusTable

The IMAPISession::GetStatusTable method provides access to the status table — a table with information about all of the MAPI resources in the session.

Quick Info

See IMAPISession : IUnknown.

HRESULT GetStatusTable(
  ULONG ulFlags,
  LPMAPITABLE FAR * lppTable
);

Parameters

ulFlags
[in] Bitmask of flags that determines the format for columns that are character strings. The following flag can be set:
MAPI_UNICODE
The string columns are in Unicode format. If the MAPI_UNICODE flag is not set, the string columns are in ANSI format.
lppTable
[out] Pointer to a pointer to the status table.

Return Values

S_OK
The table was successfully returned.

Remarks

The IMAPISession::GetStatusTable method provides access to the status table — a table with information about all of the MAPI resources in the session. There is one row in the table with information about the MAPI subsystem, one row for the MAPI spooler, one row for the integrated address book, and one row for each of the service providers in the profile.

For a complete list of required and optional columns in the status table, see Status Table.

Setting the MAPI_UNICODE flag in the ulFlags parameter affects the format of the columns returned from the following IMAPITable methods:

IMAPITable::QueryColumns

IMAPITable::QueryRows

This flag also controls the property types in the sort order returned by the IMAPITable::QuerySortOrder method.

See Also

IMAPITable::QueryColumns, IMAPITable::QueryRows, IMAPITable::QuerySortOrder, IMAPITable::SetColumns, IMAPITable::SortTable


IMAPISession::Logoff

The IMAPISession::Logoff method ends a MAPI session.

Quick Info

See IMAPISession : IUnknown.

HRESULT Logoff(
  ULONG ulUIParam,
  ULONG ulFlags,
  ULONG ulReserved
);

Parameters

ulUIParam
[in] Handle of the parent window for any dialog boxes or windows to be displayed if possible. This parameter is ignored if the MAPI_LOGOFF_UI flag is not set.
ulFlags
[in] Bitmask of flags that control the logoff operation. The following flags can be set:
MAPI_LOGOFF_SHARED
If this session is shared, all clients logged on using the shared session should be notified of the logoff in progress. The clients should log off. Any client using the shared session can set this flag. MAPI_LOGOFF_SHARED is ignored if the current session is not shared.
MAPI_LOGOFF_UI
Logoff can display a dialog box during the operation, possibly prompting the user for confirmation.
ulReserved
Reserved; must be zero.

Return Values

S_OK
The logoff operation was successful.

Remarks

The IMAPISession::Logoff method ends a MAPI session. When Logoff returns, none of the methods except for Release can be called. IMAPISession::Logoff is similar in functionality to the Simple MAPI function MAPILogoff.

Notes to Callers

When Logoff returns, release the session object by calling its IUnknown::Release method.

For more information about ending a session, see Ending a MAPI Session.

See Also

MAPILogoff


IMAPISession::MessageOptions

The IMAPISession::MessageOptions method displays a dialog box showing option properties for a particular address type and message.

Quick Info

See IMAPISession : IUnknown.

HRESULT MessageOptions(
  ULONG ulUIParam,
  ULONG ulFlags,
  LPTSTR lpszAdrType,
  LPMESSAGE lpMessage
);

Parameters

ulUIParam
[in] Handle of the parent window for the dialog box.
ulFlags
[in] Bitmask of flags that controls the format of the message option properties. The following flag can be set:
MAPI_UNICODE
The message option properties are in Unicode format. If the MAPI_UNICODE flag is not set, the message option properties are in ANSI format.
lpszAdrType
[in] Pointer to the address type for which option properties should be displayed, or NULL, indicating that all message option properties for all transport providers should be displayed.
lpMessage
[in] Pointer to the message for which option properties should be displayed.

Return Values

S_OK
The dialog box was successfully displayed.
MAPI_E_NOT_FOUND
No options were registered for the message and address type.

Remarks

The IMAPISession::MessageOptions method presents a dialog box displaying properties that relate to a particular message and addess type. These properties are under the control of the transport provider handling the address type. Users can make changes to the properties, but these changes do not take affect until the client calls the message's IMAPIProp::SaveChanges method.

Users can make changes to option properties that apply to:

  • A particular message and address type.
  • All messages for a particular address type.

Changes made to the option properties for a particular message and address type do not affect the option properties that apply to all messages.

For more information about working with message option properties, see Message and Recipient Options.


IMAPISession::OpenAddressBook

The IMAPISession::OpenAddressBook method opens the MAPI integrated address book, returning an IAddrBook pointer for further access.

Quick Info

See IMAPISession : IUnknown.

HRESULT OpenAddressBook(
  ULONG ulUIParam,
  LPCIID lpInterface,
  ULONG ulFlags,
  LPADRBOOK FAR * lppAdrBook
);

Parameters

ulUIParam
[in] Handle of the parent window for the common address dialog box and other related displays.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the address book. Passing NULL results in a pointer to the address book's standard interface, or IAddrBook, being returned.
ulFlags
[in] Bitmask of flags that controls the opening of the address book. The following flag can be set:
AB_NO_DIALOG
Suppresses the display of dialog boxes. If the AB_NO_DIALOG flag is not set, the address book providers contributing to the integrated address book can prompt the user for any necessary information.
lppAdrBook
[out] Pointer to a pointer to the address book.

Return Values

S_OK
The address book was successfully opened.
MAPI_E_UNKNOWN_CPID
The server is not configured to support the client's code page.
MAPI_E_UNKNOWN_LCID
The server is not configured to support the client's locale information.
MAPI_W_ERRORS_RETURNED
The call succeeded, but the containers of one or more address book providers could not be opened. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IMAPISession::OpenAddressBook method opens the MAPI integrated address book — a collection of the top-level containers of all of the address book providers in the profile. The pointer that is returned in the lppAdrBook parameter provides further access to the contents of the address book, allowing the caller to perform tasks such as opening individual containers, finding messaging users, and displaying common address dialog boxes.

Notes to Callers

OpenAddressBook returns MAPI_W_ERRORS_RETURNED if it cannot load one or more of the address book providers in the profile. This value is a warning, not an error value; handle it as you would S_OK. OpenAddressBook always returns a valid pointer in the lppAdrBook parameter, regardless of how many of the address book providers failed to load. Therefore, you must always call the address book's IUnknown::Release method at some point before logging off.

When OpenAddressBook returns MAPI_W_ERRORS_RETURNED, call IMAPISession::GetLastError to obtain a MAPIERROR structure containing information about the failing providers. A single MAPIERROR structure is returned that contains information supplied by all of the providers.

See Also

IMAPISession::GetLastError, MAPIERROR


IMAPISession::OpenEntry

The IMAPISession::OpenEntry method opens an object and returns an interface pointer for further access.

Quick Info

See IMAPISession : IUnknown.

HRESULT OpenEntry(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  LPCIID lpInterface,
  ULONG ulFlags,
  ULONG FAR * lpulObjType,
  LPUNKNOWN FAR * lppUnk
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the object to open.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the opened object. Passing NULL results in the object's standard interface being returned. For example, if the object to be opened is a message, the standard interface is IMessage; for folders, it is IMAPIFolder. The standard interfaces for address book objects are IDistList for a distribution list and IMailUser for a messaging user.
ulFlags
[in] Bitmask of flags that controls how the object is opened. The following flags can be used:
MAPI_BEST_ACCESS
Requests that the object be opened with the maximum network permissions allowed for the user and the maximum client application access. For example, if the client has read/write access, the object should be opened with read/write access; if the client has read-only access, the object should be opened with read-only access.
MAPI_DEFERRED_ERRORS
Allows OpenEntry to return successfully, possibly before the object is fully accessible to the calling client. If the object is not accessible, making a subsequent object call can result in an error.
MAPI_MODIFY
Requests read/write access. By default, objects are opened with read-only access, and clients should not work on the assumption that read/write access has been granted.
lpulObjType
[out] Pointer to the type of the opened object.
lppUnk
[out] Pointer to a pointer to the opened object.

Return Values

S_OK
The object was opened successfully.
MAPI_E_NO_ACCESS
An attempt was made to modify a read-only object or an attempt was made to access an object for which the user has insufficient permissions.
MAPI_E_NOT_FOUND
There is not an object associated with the entry identifier passed in lpEntryID.
MAPI_E_UNKNOWN_ENTRYID
The entry identifier passed in the lpEntryID parameter is in an unrecognizable format. This value is typically returned if the service provider that contains the object is not open.

Remarks

The IMAPISession::OpenEntry method opens a message store or address book object, returning a pointer to an interface that can be used to access the object.

Notes to Callers

Call IMAPISession::OpenEntry only when you do not know what kind of object you are opening. If you know you are opening a folder or a message, call IMsgStore::OpenEntry. If you know you are opening an address book container, a messaging user, or a distribution list, call IAddrBook::OpenEntry. These more specific methods are faster than IMAPISession::OpenEntry.

MAPI opens all objects with read-only access, unless you set the MAPI_MODIFY or MAPI_BEST_ACCESS flag in the ulFlags parameter. Setting one of these flags does not guarantee a particular type of access; the permissions that you are granted depends on the service provider, your access level, and the object. To determine the access level of the opened object, retrieve its PR_ACCESS_LEVEL property.

Calling OpenEntry and setting lpEntryID to point to the entry identifier of a message store is equivalent to calling the IMAPISession::OpenMsgStore method with the MDB_NO_DIALOG flag set. The flag settings are also equivalent, with the exception that to request read/write access with OpenMsgStore, you must set the MDB_WRITE flag rather than MAPI_MODIFY.

Check the value returned in the lpulObjType parameter to determine that the object type returned is what you expected. If the object type is not the type you expected, cast the pointer from the lppUnk parameter to a pointer of the appropriate type. For example, if you are opening a folder, cast lppUnk to a pointer of type LPMAPIFOLDER.

See Also

IAddrBook::OpenEntry, IMAPISession::OpenMsgStore, IMsgStore::OpenEntry


IMAPISession::OpenMsgStore

The IMAPISession::OpenMsgStore method opens a message store and returns an IMsgStore pointer for further access.

Quick Info

See IMAPISession : IUnknown.

HRESULT OpenMsgStore(
  ULONG ulUIParam,
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  LPCIID lpInterface,
  ULONG ulFlags,
  LPMDB FAR * lppMDB
);

Parameters

ulUIParam
[in] Handle of the parent window for the common address dialog box and other related displays.
cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the message store to be opened. The lpEntryID parameter must not be NULL.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the message store. Passing NULL results in a pointer to its standard interface being returned in the lppMDB parameter. The standard interface for a message store is IMsgStore.
ulFlags
[in] Bitmask of flags that controls how the object is opened. The following flags can be used:
MAPI_BEST_ACCESS
Requests that the message store be opened with the maximum network permissions allowed for the user and the maximum client application access. For example, if the client has read/write access, the message store should be opened with read/write access; if the client has read-only access, the message store should be opened with read-only access.
MAPI_DEFERRED_ERRORS
Allows OpenMsgStore to return successfully, possibly before the message store is fully accessible to the calling client. If the message store is not accessible, making a subsequent object call can result in an error.
MDB_NO_DIALOG
Prevents the display of logon dialog boxes. If this flag is set, and OpenMsgStore does not have enough configuration information to open the message store without the user's help, it returns MAPI_E_LOGON_FAILED. If this flag is not set, the message store provider can prompt the user to correct a name or password, to insert a disk, or to perform other actions necessary to establish connection to the message store.
MDB_NO_MAIL
The message store should not be used for sending or receiving mail. When this flag is set, MAPI does not notify the MAPI spooler that this message store is being opened.
MDB_TEMPORARY
Instructs MAPI that the message store is not permanent and should not be added to the message store table. This flag is used to log on the message store so that information can be retrieved programmatically from the profile section.
MDB_WRITE
Requests read/write access to the message store.
lppMDB
[out] Pointer to a pointer to the message store.

Return Values

S_OK
The message store was successfully opened.
MAPI_E_NO_ACCESS
An attempt was made to access a message store for which the user has insufficient permissions.
MAPI_E_NOT_FOUND
The message store indicated by lpEntryID does not exist.
MAPI_E_UNKNOWN_CPID
The server is not configured to support the client's code page.
MAPI_E_UNKNOWN_LCID
The server is not configured to support the client's locale information.
MAPI_W_ERRORS_RETURNED
The call succeeded, but the message store provider has error information available. When this warning is returned, the call should be handled as successful. To get the error information from the provider, call the IMAPISession::GetLastError method. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IMAPISession::OpenMsgStore method opens a particular message store.

Notes to Callers

The default access level for message stores is read-only. If you set the MDB_WRITE flag, you may or may not be granted read/write access. The final level of access that MAPI assigns to the message store depends on your level of access, the message store itself, and the message store provider.

If you call OpenMsgStore to open a message store with read-only access:

  • The store's PR_STORE_SUPPORT_MASK property will not have its STORE_MODIFY_OK and STORE_CREATE_OK bits set.
  • Calls to open one of the message store's messages or folders using IMAPISession::OpenEntry with the MAPI_MODIFY flag set will fail.
  • Calls to open one of the properties of the message store's messages or folders using IMAPIProp::OpenProperty and the MAPI_MODIFY will fail.
  • Calls to any of the following methods will fail:

    IMAPIFolder::CreateMessage

    IMAPIFolder::DeleteMessages

    IMAPIFolder::CreateFolder

    IMAPIFolder::DeleteFolder

    IMAPIFolder::SetMessageStatus

    IMAPIProp::SetProps

    IMAPIProp::DeleteProps

  • Calls to the following methods fail if the destination for the copied message is read-only, whether it be the same as the source message store or another read-only store:

    IMAPIFolder::CopyMessages

    IMAPIFolder::CopyFolder

    IMAPIProp::CopyTo


IMAPISession::OpenProfileSection

The IMAPISession::OpenProfileSection method opens a section of the current profile and returns an IProfSect pointer for further access.

Quick Info

See IMAPISession : IUnknown.

HRESULT OpenProfileSection(
  LPMAPIUID lpUID,
  LPCIID lpInterface,
  ULONG ulFlags,
  LPPROFSECT FAR * lppProfSect
);

Parameters

lpUID
[in] Pointer to the MAPIUID structure identifying the profile section.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the profile section. Passing NULL results in a pointer to its standard interface being returned in the lppProfSect parameter. The standard interface for a profile section is IProfSect.
ulFlags
[in] Bitmask of flags that controls access to the profile section. The following flags can be set:
MAPI_DEFERRED_ERRORS
Allows OpenProfileSection to return successfully, possibly before the profile section is fully accessible to the calling client. If the profile section is not accessible, making a subsequent call to it can result in an error.
MAPI_MODIFY
Requests read/write access. By default, profile sections are opened with read-only access, and clients should not work on the assumption that read/write access has been granted.
lppProfSect
[out] Pointer to a pointer to the profile section.

Return Values

S_OK
The profile section was successfully opened.
MAPI_E_NO_ACCESS
An attempt was made to access a profile section for which the caller has insufficient permissions.
MAPI_E_NOT_FOUND
The requested profile section does not exist.

Remarks

The IMAPISession::OpenProfileSection method opens a profile section — or object that supports the IProfSect interface. Profile sections are used for reading information from and writing information to the session profile.

OpenProfileSection cannot be used to open profile sections owned by individual service providers.

Notes to Callers

Multiple clients can open a profile section with read-only access, but only one client can open a profile section with read/write access. If another client has a profile section open that you attempt to open by calling OpenProfileSection with the MAPI_MODIFY flag set, the call will fail, returning MAPI_E_NO_ACCESS.

A read-only open operation fails if the section is open for writing.

You can create a profile section by calling OpenProfileSection with the MAPI_MODIFY flag and a non-existent MAPIUID structure in the lpUID parameter. Make sure you specify MAPI_MODIFY. If you set lpUID to point to a nonexistent MAPIUID and OpenProfileSection is set to use the default access mode of read-only, the call fails with MAPI_E_NOT_FOUND.

See Also

IMAPIProp : IUnknown, IProfSect : IMAPIProp, MAPIUID


IMAPISession::PrepareForm

The IMAPISession::PrepareForm method creates a numeric token to be used by the IMAPISession::ShowForm method to access a message.

Quick Info

See IMAPISession : IUnknown.

HRESULT PrepareForm(
  LPCIID lpInterface,
  LPMESSAGE lpMessage,
  ULONG FAR * lpulMessageToken
);

Parameters

lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the message. Passing NULL results in the standard interface, or IMessage, being used. The lpInterface parameter must be NULL or IID_IMessage.
lpMessage
[in] Pointer to the message to be displayed in the form.
lpulMessageToken
[out] Pointer to a message token, which is used by the IMAPISession::ShowForm method to access the message pointed to by lpMessage.

Return Values

S_OK
The form preparation was successful.

Remarks

The IMAPISession::PrepareForm method creates a message token for the message pointed to by the lpMessage parameter and calls the message's IUnknown::AddRef method. This token is passed in the ulMessageToken parameter to IMAPISession::ShowForm.

Notes to Callers

If the call to PrepareForm succeeds, release the message pointed to by lpMessage by calling its IUnknown::Release method before calling ShowForm. Failure to release the message before calling ShowForm can cause memory leaks.

See Also

IMAPISession::ShowForm


IMAPISession::QueryDefaultMessageOpt

The IMAPISession::QueryDefaultMessageOpt method retrieves the message option properties for a particular address type.

Quick Info

See IMAPISession : IUnknown.

HRESULT QueryDefaultMessageOpt(
  LPTSTR lpszAdrType,
  ULONG ulFlags,
  ULONG FAR * lpcValues,
  LPSPropValue FAR * lppOptions
);

Parameters

lpszAdrType
[in] Pointer to an address type.
ulFlags
[in] Bitmask of flags that controls the format of the string property values pointed to by lppOptions. The following flag can be set:
MAPI_UNICODE
The property values should be in Unicode format. If the MAPI_UNICODE flag is not set, the property values should be in ANSI format.
lpcValues
[out] Pointer to a count of property values pointed to by the lppOptions parameter.
lppOptions
[out] Pointer to a pointer to an array of SPropValue structures describing message option properties.

Return Values

S_OK
The message option properties were successfully returned.

Remarks

The IMAPISession::QueryDefaultMessageOpt method retrieves the one or more message option properties that a transport provider supports for the address type pointed to by the lpszAdrType parameter. Message option properties control a message's behavior after it is submitted to the transport provider; they are part of the message envelope, not its content.

The property value array pointed to by lppOptions includes the property tags and values for each of the message option properties.


IMAPISession::QueryIdentity

The IMAPISession::QueryIdentity method returns the entry identifier of the object that provides the primary identity for the session.

Quick Info

See IMAPISession : IUnknown.

HRESULT QueryIdentity(
  ULONG FAR * lpcbEntryID,
  LPENTRYID FAR * lppEntryID
);

Parameters

lpcbEntryID
[out] Pointer to the count of bytes in the entry identifier pointed to by the lppEntryID parameter.
lppEntryID
[out] Pointer to a pointer to the entry identifier of the object providing the primary identity.

Return Values

S_OK
The primary identity was successfully returned.
MAPI_W_NO_SERVICE
The call succeeded, but there is no primary identity for the session. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IMAPSession::QueryIdentity method retrieves the primary identity for the current session. The primary identity is an object, typically a messaging user, that represents the user of a session. Although many service providers in multiple message services can provide the primary identity for a session, MAPI designates a single service provider. The service provider supplying the primary identity sets the following:

  • STATUS_PRIMARY_IDENTITY flag in the PR_RESOURCE_FLAGS property
  • PR_IDENTITY_DISPLAY
  • PR_IDENTITY_ENTRYID
  • PR_IDENTITY_SEARCH_KEY

If the service provider supplying the primary identity belongs to a message service, the other service providers in the message service also set the PR_IDENTITY properties. These properties are published in the session's status table.

If possible, QueryIdentity returns the value for the PR_IDENTITY_ENTRYID property from the status row tagged with STATUS_PRIMARY_IDENTITY. If the PR_IDENTITY_ENTRYID property is missing from the primary identity row, QueryIdentity returns a one-off entry identifier built with other information from that row.

If the STATUS_PRIMARY_IDENTITY flag is missing from all of the PR_RESOURCE_FLAG columns in the status table, QueryIdentity returns the first entry identifier that it finds. When there is no appropriate entry identifier to return, QueryIdentity succeeds with the warning MAPI_W_NO_SERVICE and points lppEntryID to a hard-coded entry identifier.

Notes to Callers

You can call the IMsgServiceAdmin::SetPrimaryIdentity method to assign a message service the task of supplying the session's primary identity.

Another way to retrieve the primary identity is by searching the status table for the row with the PR_RESOURCE_FLAGS columns set to STATUS_PRIMARY_IDENTITY. For more information on this alternate way of retrieving identity information, see Using the Status Table and Status Objects.

When you have finished using the entry identifier for the primary identity returned by QueryIdentity, free its memory by calling the MAPIFreeBuffer function.

For more information about identity in general, see Primary Identity.

For more information about retrieving MAPI session identity, see Retrieving Primary and Provider Identity.

See Also

IMAPISession::OpenEntry, IMsgServiceAdmin::SetPrimaryIdentity, MAPIFreeBuffer


IMAPISession::SetDefaultStore

The IMAPISession::SetDefaultStore method establishes a message store as the default message store for the session.

Quick Info

See IMAPISession : IUnknown.

HRESULT SetDefaultStore(
  ULONG ulFlags,
  ULONG cbEntryID,
  LPENTRYID lpEntryID
);

Parameters

ulFlags
[in] Bitmask of flags that controls the setting of the default message store. These flags are mutually exclusive; only one of the following flags can be set:
MAPI_DEFAULT_STORE
Establishes the message store as the session default. Updates the message store's status table row by setting the STATUS_DEFAULT_STORE flag in the PR_RESOURCE_FLAGS column.
MAPI_PRIMARY_STORE
Establishes the message store as the store to be used at logon. If the message store is not the default store, clients should make it the default. Updates the message store's status table row by setting the STATUS_PRIMARY_STORE flag in the PR_RESOURCE_FLAGS column.

MAPI_SECONDARY_STORE

Establishes the message store as the store to be used at logon if the primary message store is not available. If a client cannot open the primary store, it should open the secondary store and set it as the default. Updates the message store's status table row by setting the STATUS_SECONDARY_STORE flag in the PR_RESOURCE_FLAGS column.

MAPI_SIMPLE_STORE_PERMANENT
Establishes the message store as the session default for Simple MAPI and CMC clients and sets the STATUS_SIMPLE_STORE flag in the message store's PR_RESOURCE_FLAGS property in its status table row, message store table row, and in the session profile.
MAPI_SIMPLE_STORE_TEMPORARY
Establishes the message store as the session default for Simple MAPI and CMC clients and sets the STATUS_SIMPLE_STORE flag in the message store's PR_RESOURCE_FLAGS property in its status table row and message store table row. The profile is not modified.
cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the message store intended as the default. If a client passes NULL in lpEntryID, no message store is selected as the default.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

The IMAPISession::SetDefaultStore method establishes a message store as one of the following:

  • Default message store for the session
  • Primary message store for the session
  • Secondary message store for the session
  • Temporary or permanent message store that can be used with Simple MAPI

To establish a message store as the default, the message store must have the following flags set in its PR_STORE_SUPPORT_MASK property:

STORE_SUBMIT_OK

STORE_CREATE_OK

STORE_MODIFY_OK

Notes to Callers

You can determine the default message store for the session by retrieving the status table and searching for the setting of the STATUS_DEFAULT_STORE flag in the PR_RESOURCE_FLAGS column. The row with this setting represents the message store designated as the session default.

When either the MAPI_DEFAULT_STORE or the MAPI_SIMPLE_STORE_PERMANENT flag is set, MAPI updates the profile, message store table, and status table.

Whenever a change is made to the message store default setting, the following notifications are generated:

  • An fnevTableModified event notification is issued for each of the affected rows in both the message store and status table.
  • An internal notification is issued to the MAPI spooler. Operations already in progress are completed without change; new operations involving the default message store, such as message downloading, are processed for the new default store.

See Also

PR_RESOURCE_FLAGS, PR_STORE_SUPPORT_MASK, TABLE_NOTIFICATION


IMAPISession::ShowForm

The IMAPISession::ShowForm method displays a form.

Quick Info

See IMAPISession : IUnknown.

HRESULT ShowForm(
  ULONG ulUIParam,
  LPMDB lpMsgStore,
  LPMAPIFOLDER lpParentFolder,
  LPCIID lpInterface,
  ULONG ulMessageToken,
  LPMESSAGE lpMessageSent,
  ULONG ulFlags,
  ULONG ulMessageStatus,
  ULONG ulMessageFlags,
  ULONG ulAccess,
  LPSTR lpszMessageClass
);

Parameters

ulUIParam
[in] Handle of the parent window for the form. The ulUIParam parameter must not be NULL if the form has been created using Microsoft® Electronic Forms Designer. The ulUIParam parameter can be NULL if the form has been created using C or C++.
lpMsgStore
[in] Pointer to the message store containing the folder pointed to by the lpParentFolder parameter.
lpParentFolder
[in] Pointer to the folder in which the message associated with the ulMessageToken parameter was created.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the message being displayed in the form. The lpInterface parameter must be NULL or IID_IMessage. Passing NULL results in the standard interface, or IMessage, being used.
ulMessageToken
[in] Token associated with the message to be displayed in the form. The ulMessageToken parameter must be set to the contents of the lpulMessageToken parameter from the preceding call to IMAPISession::PrepareForm.
lpMessageSent
Reserved; must be NULL.
ulFlags
[in] Bitmask of flags that controls how and whether the message is saved. The following flags can be set:
MAPI_NEW_MESSAGE
The message has never been saved — that is, its IMAPIProp::SaveChanges method has never been called.
MAPI_POST_MESSAGE
The message should be saved to its parent folder. The message is not processed for sending but posted to the folder instead. If this flag is not set, the message is copied to the Outbox and processed for sending.
ulMessageStatus
[in] Bitmask of flags copied from the PR_MSG_STATUS property of the message associated with the token in the ulMessageToken parameter. The flags provide information on the state of the message.
ulMessageFlags
[in] Bitmask of flags copied from the PR_MESSAGE_FLAGS property of the message associated with the token in the ulMessageToken parameter. These flags provide further information on the state of the message.
ulAccess
[in] Flag indicating the access level for the message being displayed in the form. This information is copied from the PR_ACCESS property of the message associated with the token in the ulMessageToken parameter.
lpszMessageClass
[in] Pointer to the message class of the message being displayed in the form, copied from the PR_MESSAGE_CLASS property of the message associated with the token in the ulMessageToken parameter.

Return Values

S_OK
The form was successfully displayed.
MAPI_E_USER_CANCEL
The user canceled the operation, typically by clicking the Cancel button in a dialog box.

Remarks

The IMAPISession::ShowForm method displays a message form that has been prepared by the IMAPISession::PrepareForm method.

Notes to Callers

You should only have a single reference to the message passed in the PrepareForm method's lpMessage parameter.

Be aware that form implementations can return error values other than the ones documented by MAPI. If you are able to use these error values to make a more accurate determination of the error condition, do so. Otherwise, handle these errors in the same manner as you would handle MAPI_E_CALL_FAILED.


IMAPISession::Unadvise

The IMAPISession::Unadvise method cancels the sending of notifications previously set up with a call to the IMAPISession::Advise method.

Quick Info

See IMAPISession : IUnknown.

HRESULT Unadvise(
  ULONG ulConnection
);

Parameters

ulConnection
[in] Connection number associated with an active notification registration. The value of ulConnection must have been returned by a previous call to IMAPISession::Advise.

Return Values

S_OK
The registration was successfully canceled.

Remarks

The IMAPISession::Unadvise method cancels a registration for notification. Unadvise releases its pointer to the caller's advise sink, which it received in the Advise call used for registration.

Generally, Unadvise calls the advise sink's IUnknown::Release method during the Unadvise call, but if another thread is in the process of calling the advise sink's IMAPIAdviseSink::OnNotify method, the Release call is delayed until the OnNotify method returns.

See Also

IMAPIAdviseSink::OnNotify, IMAPISession::Advise


IMAPIStatus : IMAPIProp

MAPI implements the IMAPIStatus interface to provide status information about the MAPI subsystem, the integrated address book and the MAPI spooler. A service provider implements IMAPIStatus to supply information about its own status.

Quick Info

Header file: | MAPIDEFS.H
Exposed by: | Status objects
Implemented by: | Service providers and MAPI
Called by: | Client applications
Interface identifier: | IID_IMAPIStatus
Pointer type: | LPMAPISTATUS
Transaction model: | Nontransacted

Vtable Order

ValidateState | Confirms the external status information available for the MAPI resource or the service provider. This method is supported in all status objects.
SettingsDialog | Displays a property sheet enabling the user to change a service provider's configuration. This method is not supported in status objects implemented by MAPI.
ChangePassword | Modifies a service provider's password without displaying a user interface. This method is optionally supported in status objects implemented by service providers.
FlushQueues | Forces all messages waiting to be sent or received to be immediately uploaded or downloaded. This method is supported by the MAPI spooler status object and status objects implemented by transport providers.

Required properties | Access
PR_DISPLAY_NAME | Read/write
PR_PROVIDER_DISPLAY | Read/write
PR_PROVIDER_DLL_NAME | Read-only
PR_RESOURCE_FLAGS | Read-only
PR_RESOURCE_METHODS | Read-only
PR_RESOURCE_TYPE | Read-only
PR_STATUS_CODE | Read-only

Remarks

The status objects implemented by MAPI support the following methods:

Status object | Supported methods
MAPI subsystem | ValidateState only
MAPI address book | ValidateState only
MAPI spooler | ValidateState and FlushQueues

The status objects implemented by MAPI are required to have a read-only version of the methods of the IMAPIProp interface and support the IMAPIStatus::ValidateState method. Transport providers are strongly recommended to also support FlushQueues. All providers are encouraged to support SettingsDialog and support for ChangePassword is optional.

Clients use status objects to perform configuration and to learn about the state of the session. They access a status object by calling the OpenStatusEntry method of a service provider logon object or IMAPISession::GetStatusTable to retrieve the status object.


IMAPIStatus::ChangePassword

The IMAPIStatus::ChangePassword method modifies a service provider's password without displaying a user interface.

Quick Info

See IMAPIStatus : IMAPIProp.

HRESULT ChangePassword(
  LPTSTR lpOldPass,
  LPTSTR lpNewPass,
  ULONG ulFlags
);

Parameters

lpOldPass
[in] Pointer to the old password.
lpNewPass
[in] Pointer to the new password.
ulFlags
[in] Bitmask of flags that controls the format of the passwords. The following flag can be set:
MAPI_UNICODE
The passwords are in Unicode format. If the MAPI_UNICODE flag is not set, the passwords are in ANSI format.

Return Values

S_OK
The password modification was successful.
MAPI_E_NO_ACCESS
The old password pointed to by lpOldPass is invalid.
MAPI_E_NO_SUPPORT
The status object does not support this operation, as indicated by the absence of the STATUS_CHANGE_PASSWORD flag in the status object's PR_RESOURCE_METHODS property.

Remarks

Not all status objects support the IMAPIStatus::ChangePassword method. It is supported only by service providers that require clients to enter a password. None of the status objects implemented by MAPI support the password change operation.

ChangePassword modifies a password programmatically, without user interaction.

Notes to Implementers

Remote transport providers implement ChangePassword as specified here. There are no special considerations.

See Also

PR_RESOURCE_METHODS


IMAPIStatus::FlushQueues

The IMAPIStatus::FlushQueues method forces all messages waiting to be sent or received to be immediately uploaded or downloaded.

Quick Info

See IMAPIStatus : IMAPIProp.

HRESULT FlushQueues(
  ULONG ulUIParam,
  ULONG cbTargetTransport,
  LPENTRYID lpTargetTransport,
  ULONG ulFlags
);

Parameters

ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays.
cbTargetTransport
[in] Count of bytes in the entry identifier pointed to by the lpTargetTransport parameter. The cbTargetTransport parameter is set only on calls to the MAPI spooler's status object. For calls to a transport provider, the cbTargetTransport parameter is set to zero.
lpTargetTransport
[in] Pointer to the entry identifier of the transport provider that is to flush its message queues. The lpTargetTransport parameter is set only on calls to the MAPI spooler's status object. For calls to a transport provider, the lpTargetTransport parameter is set to NULL.
ulFlags
[in] Bitmask of flags that controls the flush operation. The following flags can be set:
FLUSH_ASYNC_OK
The flush operation can occur asynchronously. This flag only applies to the MAPI spooler's status object.
FLUSH_DOWNLOAD
The inbound message queues should be flushed.
FLUSH_FORCE
The flush operation should occur regardless, in spite of the possibility of performance degradation. This flag must be set when targeting an asynchronous transport provider.
FLUSH_NO_UI
The status object should not display a progress indicator. This flag is used only by the MAPI spooler; providers ignore this flag.
FLUSH_UPLOAD
The outbound message queues should be flushed.

Return Values

S_OK
The flush operation was successful.
MAPI_E_BUSY
Another operation is in progress; it should be allowed to complete, or it should be stopped, before this operation can be initiated.
MAPI_E_NO_SUPPORT
The status object does not support this operation, as indicated by the absence of the STATUS_FLUSH_QUEUES flag in the status object's PR_RESOURCE_METHODS property.

Remarks

The IMAPIStatus::FlushQueues method requests that the MAPI spooler or a transport provider immediately send all messages in the outbound queue or receive all messages from the inbound queue. FlushQueues is only implemented by the MAPI spooler status object and by status objects supplied by transport providers.

The processing involved with FlushQueues can take a long time. By default, the MAPI spooler's implementation displays a progress indicator to keep the user informed. If the FLUSH_NO_UI flag is set in the ulFlags parameter, no progress indicator is displayed. Transport providers never display a progress indicator as part of their flush operation; they always ignore the FLUSH_NO_UI flag.

MAPI_E_BUSY should be returned for asynchronous requests so that clients can continue work.

By default, FlushQueues is a synchronous operation; control does not return to the caller until the flush has completed. Only the flush operation performed by the MAPI spooler can be asynchronous; clients request this behavior by setting the FLUSH_ASYNC_OK flag.

Notes to Implementers

A remote transport provider's implementation of FlushQueues sets bits in the PR_STATUS_CODE property in the logon object's status row to control how queues are flushed. If a remote viewer passes in the FLUSH_UPLOAD flag, the FlushQueues method should set the STATUS_INBOUND_ENABLED and STATUS_INBOUND_ACTIVE bits. If a remote viewer passes in the FLUSH_DOWNLOAD flag, the FlushQueues method should set the STATUS_OUTBOUND_ENABLED and STATUS_OUTBOUND_ACTIVE bits. FlushQueues should then return S_OK. The MAPI spooler will then initiate the appropriate actions to upload and download messages.

Notes to Callers

When calling the MAPI spooler status object, this is a directive to transfer all messages either to or from the appropriate transport provider. When calling an individual transport provider's status object, only the messages for that provider are affected.

See Also

PR_RESOURCE_METHODS


IMAPIStatus::SettingsDialog

The IMAPIStatus::SettingsDialog method displays a property sheet enabling the user to change a service provider's configuration.

Quick Info

See IMAPIStatus : IMAPIProp.

HRESULT SettingsDialog(
  ULONG ulUIParam,
  ULONG ulFlags
);

Parameters

ulUIParam
[in] Handle of the parent window for the configuration property sheet.
ulFlags
[in] Bitmask of flags that controls the display of the property sheet. The following flag can be set:
UI_READONLY
Suggests that the provider not enable users to change configuration properties. This flag is only a suggestion; it can be ignored.

Return Values

S_OK
The configuration property sheet was displayed successfully.
MAPI_E_NO_SUPPORT
The status object does not support this method as indicated by the absence of the STATUS_SETTINGS_DIALOG flag in the PR_RESOURCE_METHODS property.

Remarks

The IMAPIStatus::SettingsDialog method displays a configuration property sheet. MAPI recommends that all service providers support the SettingsDialog method, but it is not required. Service providers can implement their own property sheets or use the implementation supplied in the support object's IMAPISupport::DoConfigPropsheet method. DoConfigPropsheet builds a read/write property sheet.

Notes to Implementers

If a remote transport provider has any settings, it should do the following:

  • Open the transport provider's profile section.
  • Get the transport provider's property settings from the profile.
  • Display the property settings in a dialog box.
  • If the dialog box allows editing of the property settings, check that the new settings are valid and store them back in the transport provider's profile section.
  • Return S_OK, or any error values returned during the preceeding steps.

Notes to Callers

You can use the property sheet displayed through SettingsDialog to perform a variety of tasks, such as:

  • Specify a default message store.
  • Specify a transport order.
  • Specify a default address book container for browsing.
  • Specify a search order for resolving ambiguous names.
  • Specify a default personal address book.

Service providers can implement property sheets that are read/write, read-only, or a mixture of access modes, depending on the property. Service providers can implement different access on individual properties by setting property restrictions. The default mode for property sheets is read/write. You can request read-only displays by setting the UI_READONLY flag in your calls to SettingsDialog. Service providers that are able to honor the request can do so. However, because some service providers cannot override the default mode, you must be prepared to handle property sheets of either type.

Because a user interface is always involved in this operation, only interactive clients should call SettingsDialog.


IMAPIStatus::ValidateState

The IMAPIStatus::ValidateState method confirms the external status information available for the MAPI resource or the service provider.

Quick Info

See IMAPIStatus : IMAPIProp.

HRESULT ValidateState(
  ULONG ulUIParam,
  ULONG ulFlags
);

Parameters

ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays.
ulFlags
[in] Bitmask of flags that controls the validation. The following flags can be set:
ABORT_XP_HEADER_OPERATION
The user has canceled the operation, typically by clicking the Cancel button in the corresponding dialog box. The status object has two options:
  • Continue working on the operation
  • Abort the operation and return MAPI_E_USER_CANCELED
CONFIG_CHANGED
One or more of the status object's configuration properties has changed. Clients can set this flag to allow the MAPI spooler to dynamically correct critical transport provider failures.
FORCE_XP_CONNECT
The status object should perform a connection. When this flag is used with the REFRESH_XP_HEADER_CACHE or PROCESS_XP_HEADER_CACHE flag, the connection occurs without caching.
FORCE_XP_DISCONNECT
The status object should perform a disconnect operation. When this flag is used with the REFRESH_XP_HEADER_CACHE or PROCESS_XP_HEADER_CACHE flag, the disconnection occurs without caching.
PROCESS_XP_HEADER_CACHE
Entries in the header cache table should be processed, all messages marked with the MSGSTATUS_REMOTE_DOWNLOAD flag should be downloaded, and all messages marked with the MSGSTATUS_REMOTE_DELETE flag should be deleted. Messages that have both MSGSTATUS_REMOTE_DOWNLOAD and MSGSTATUS_REMOTE_DELETE set should be moved.
REFRESH_XP_HEADER_CACHE
For a remote transport provider, a new list of message headers should be downloaded and all flags marking message status should be cleared.
SUPPRESS_UI
Prevents the status object from displaying a user interface as part of the operation.

Return Values

S_OK
The validation was successful.
MAPI_E_BUSY
Another operation is in progress; it should be allowed to complete, or it should be stopped, before this operation should be initiated.
MAPI_E_NO_SUPPORT
The status object does not support the validation method, as indicated by the absence of the STATUS_VALIDATE_STATE flag in the PR_RESOURCE_METHODS property.
MAPI_E_USER_CANCEL
The user canceled the validation operation, typically by clicking the Cancel button in a dialog box. This value is only returned by remote transport providers.

Remarks

The IMAPIStatus::ValidateState method checks the state of a resource associated with a status object. ValidateState is the only method in the IMAPIStatus interface that is required for all status objects.

The exact behavior of this method depends on the implementation. The following table describes the implementation of each of the different types of status objects:

Status object | ValidateState implementation
MAPI subsystem | Validates the state of all of the resources owned by the currently active service providers and the subsystem itself.
MAPI spooler | Performs a logon of all transport providers, regardless of whether they are already logged on.
MAPI address book | Checks the entries in its profile section.
Service provider | Depends on the type of provider and the flags set in the ulFlags parameter.

Notes to Implementers

The ValidateState method is called by remote client applications to start remote processing for various actions. This method exists primarily to set status bits to communicate with the MAPI spooler rather than to actually do any work. Typically, the transport provider sets flags in its status row which indicate to the MAPI spooler what actions need to be initiated to complete the client's request. In this model of client-transport-spooler interaction, the actions requested by the client are asynchronous, in that ValidateState returns before the requested actions are complete. However, actions which do not necessarily involve the underlying messaging system, or which involve a transport-specific interface, can be synchronous. The client application passes in a bitmask of flags to specify which actions the remote transport provider should take. The flags are:

ABORT_XP_HEADER_OPERATION
If possible, the remote transport provider should cancel any operations involving downloading headers. To do this, the transport provider must set the following property values in the logon object's status row:
  • Clear the STATUS_INBOUND_ENABLED and STATUS_INBOUND_ACTIVE bits in the PR_STATUS_CODE property to tell the MAPI spooler to cease the inbound flush process for this transport provider.
  • Set the STATUS_OFFLINE bit in the PR_STATUS_CODE property.
  • Set the PR_REMOTE_VALIDATE_OK property to TRUE.
  • Set the PR_STATUS_STRING property to some string indicating the transport provider's status to the user.
  • Return S_OK

However, if the operation in progress cannot be canceled, ValidateState should return MAPI_E_BUSY.

FORCE_XP_CONNECT
A remote transport provider should never establish a connection to a shared resource, for example, a modem or COM port, outside the context of the MAPI spooler-transport interaction involved in the IXPLogon::FlushQueues method. If ValidateState is called with this flag, your transport provider should do the following:
  • Set some internal status flag to indicate that the remote connection needs to be established when the FlushQueues method is called.
  • Set the proper values in the status table to cause the MAPI spooler to initiate the queue flushing process.
  • When flushing of queues has completed, release the shared resource.
  • Clear the STATUS_OFFLINE bit in the PR_STATUS_CODE property.
  • Return S_OK.
FORCE_XP_DISCONNECT
The remote transport provider should release its connection to the messaging system resources. After doing so, it should:
  • Set the STATUS_OFFLINE bit in the PR_STATUS_CODE property.
  • Return S_OK.
PROCESS_XP_HEADER_CACHE
The remote transport provider should process remote messages and upload any messages that have been deferred. To do this the transport provider must set the following property values in the logon object's status row:
  • Set the PR_STATUS_STRING property to a string indicating the transport provider's status to the user.
  • Set the STATUS_OUTBOUND_ENABLED and STATUS_OUTBOUND_ACTIVE bits in the PR_STATUS_CODE property.
  • Set the PR_REMOTE_VALIDATE_OK property in the transport provider's status row to FALSE.
  • If another operation is in progress (such as downloading headers) when ValidateState is called, ValidateState should return MAPI_E_BUSY.
  • Execute the code for processing the REFRESH_XP_HEADER_CACHE flag as well to satisfy requirements of the Microsoft Exchange client.
REFRESH_XP_HEADER_CACHE
The remote transport provider should retrieve any new message headers from the messaging system. To do this, the transport provider must:
  • Set the PR_STATUS_STRING property to a string indicating the transport provider's status to the user.
  • Set the STATUS_INBOUND_ENABLED and STATUS_INBOUND_ACTIVE bits in the PR_STATUS_CODE property.
  • Clear the STATUS_OFFLINE bit in the PR_STATUS_CODE property.
  • Set the STATUS_ONLINE bit in the PR_STATUS_CODE property.
  • Set the PR_REMOTE_VALIDATE_OK property in the transport provider's status row to FALSE.
  • Return MAPI_E_BUSY.
SHOW_XP_SESSION_UI
If your transport provider has any pieces of user interface for processing the message headers — such as a dialog box confirming downloading of messages — then that dialog box should be displayed. Otherwise, ValidateState can return MAPI_E_NO_SUPPORT.

If any flags other than these are passed in, ValidateState should return MAPI_E_UNKNOWN_FLAGS.

The client's call to the transport provider will often be to the IMAPIStatus::ValidateState method. It is important during the processing of ValidateState that the transport provider not perform any actions which allocate scarce system resources, such as a modem or COM port. The reason for this is because the MAPI spooler will, at times, need to flush queues on more than one transport provider. However, the client is allowed to call any transport provider's ValidateState method at any time. If your transport provider attempts to allocate a scarce resource during the processing of ValidateState, an error can result due to conflict with another transport provider that the MAPI spooler has instructed to flush its queues. If you allow all scarce resource allocations to happen under the direction of the MAPI spooler, such conflicts will be avoided. Your transport provider should support the PR_REMOTE_VALIDATE_OK property so that client applications can detect when your transport provider is busy or waiting for the MAPI spooler to initiate an action.

Notes to Callers

Because this method can result in other calls being made that take some time, ValidateState can return MAPI_E_BUSY to inform you that this method is dependent upon another operation's completion and that operation is still in progress. You should wait until the pending operation has completed before attempting another task.

You have the most control over your calls to transport provider status objects. You can pass one or more flags to ValidateState that affect the transport provider's operations. For example, if you set the flag ABORT_XP_HEADER_OPERATION, this indicates that the user has canceled the validation. Transport providers can choose to abort — returning MAPI_E_USER_CANCELED — or continue.

The CONFIG_CHANGED flag can be set on a call to either the status object of a service provider or the MAPI spooler to indicate that a configuration option has been altered. You can use CONFIG_CHANGED to dynamically reconfigure a transport provider. When called on a service provider's status object, the provider responds with a call to IMAPISupport::SpoolerNotify to alert the MAPI spooler of the change. When called on the MAPI spooler's status object, the spooler calls IXPLogon::AddressTypes for each of the active transport providers and IMAPISession::MessageOptions. AddressTypes informs the MAPI spooler of a transport's supported address types; MessageOptions invokes the display of a property sheet showing a transport's message option properties. Some service providers also display a progress indicator if the validation is expected to take a long time. Displaying a progress indicator is helpful, but not required.

When the SUPPRESS_UI flag is set, none of the configuration property sheets can be displayed nor can any progress dialog boxes.


IMAPISupport : IUnknown

The IMAPISupport interface provides implementations for tasks that are commonly performed by service providers and message service entry point functions. Service providers receive a pointer to their support object when MAPI calls their provider object's logon method; message services receive their support object pointer in the call to their entry point function.

Quick Info

Header file: | MAPISPI.H
Exposed by: | Support objects
Implemented by: | MAPI
Called by: | Service providers
Interface identifier: | IID_IMAPISup
Pointer type: | LPMAPISUP

Vtable Order

GetLastError | Returns a MAPIERROR structure containing information about the previous support object error.
GetMemAllocRoutines | Retrieves the addresses of the MAPI memory allocation and deallocation functions: MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer.
Subscribe | Registers an advise sink to receive notifications through MAPI.
Unsubscribe | Cancels the responsibility for sending notifications that was previously established with a call to the IMAPISupport::Subscribe method.
Notify | Sends a notification of a specified event to an advise source that originally registered for the notification through IMAPISupport::Subscribe.
ModifyStatusRow | Modifies the status table by adding a new row or modifying an existing row.
OpenProfileSection | Opens a section of the current profile and returns an IProfSect pointer for further access
RegisterPreprocessor | Registers a transport provider's preprocessor function, a function that conforms to the PreprocessMessage prototype.
NewUID | Creates a new MAPIUID structure to be used as a unique identifier.
MakeInvalid | Marks an object as unusable.
SpoolerYield | Gives control of the CPU to the MAPI spooler so that it can perform any tasks it deems necessary.
SpoolerNotify | Notifies the MAPI spooler of a change in status or a request for service.
CreateOneOff | Creates an entry identifier for a one-off address.
SetProviderUID | Registers a MAPIUID structure that uniquely represents the service provider.
CompareEntryIDs | Compares two entry identifiers to determine if they refer to the same object.
OpenTemplateID | Opens a recipient entry in a foreign address book provider.
OpenEntry | Opens an object and returns an interface pointer for further access.
GetOneOffTable | Returns a pointer to the MAPI one-off table — a list of templates supported by all address book providers for creating new recipients.
Address | Displays the common address dialog box.
Details | Displays a modal dialog box showing details about a particular address book entry.
NewEntry | Adds a new recipient directly to an address book container or to the recipient list of an outgoing message.
DoConfigPropsheet | Displays a configuration property sheet.
CopyMessages | Copies or moves messages from one folder to another folder.
CopyFolder | Copies or moves a folder from its current parent folder to another parent folder.
DoCopyTo | Copies or moves all properties of one object, except for specifically excluded properties, to another object.
DoCopyProps | Copies or moves one or more properties of an object to another object.
DoProgressDialog | Retrieves a progress object for displaying a progress indicator.
ReadReceipt | Generates a read or nonread report for a message.
PrepareSubmit | Prepares a message for submission to the MAPI spooler.
ExpandRecips | Completes a message's recipient list, expanding particular distribution lists.
DoSentMail | Performs processing on a sent message.
OpenAddressBook | Provides access to the address book.
CompleteMsg | Performs postprocessing on a message.
StoreLogoffTransports | Requests the orderly release of a message store.
StatusRecips | Generates delivery and nondelivery reports.
WrapStoreEntryID | Converts a message store's internal entry identifier to an entry identifier in the MAPI standard format.
ModifyProfile | Makes the profile section for a message store provider permanent.
IStorageFromStream | Implements a storage object to access a stream.
GetSvcConfigSupportObj | Creates a message service support object.

Remarks

There are four different support objects, one for address book, message store, and transport providers and one for message services. Service providers and message services call the methods in their support objects as part of their implementations of other interface methods. Each different support object has complete implementations of the methods that are applicable to its caller; the methods that are not applicable return MAPI_E_NO_SUPPORT.

Address book provider support objects have implementations for the following methods:

Address | CompareEntryIDs | CreateOneOff
Details | DoConfigPropsheet | DoProgressDialog
GetLastError | GetMemAllocRoutines | GetOneOffTable
IStorageFromStream | GetSvcConfigSupportObj | MakeInvalid
ModifyStatusRow | NewEntry | NewUID
Notify | OpenAddressBook | OpenEntry
OpenProfileSection | OpenTemplateID | SetProviderUID
Subscribe | Unsubscribe | WrapStoreEntryID

Message store provider support objects have implementations for the following methods:

CompareEntryIDs | CompleteMsg | CopyFolder
CopyMessages | CreateOneOff | DoCopyProps
DoCopyTo | DoConfigPropsheet | DoProgressDialog
DoSentMail | ExpandRecips | GetLastError
GetMemAllocRoutines | GetSvcConfigSupportObj | MakeInvalid
IStorageFromStream | ModifyProfile | ModifyStatusRow
NewUID | Notify | OpenAddressBook
OpenEntry | OpenProfileSection | PrepareSubmit
ReadReceipt | SetProviderUID | SpoolerNotify
StoreLogoffTransports | Subscribe | Unsubscribe
WrapStoreEntryID |  |

Transport provider support objects have implementations for the following methods:

DoConfigPropsheet | CompareEntryIDs | CreateOneOff
GetMemAllocRoutines | GetSvcConfigSupportObj | GetLastError
IStorageFromStream | MakeInvalid | ModifyStatusRow
OpenAddressBook | RegisterPreprocessor | NewUID
Notify | OpenProfileSection | OpenEntry
StatusRecips | SpoolerNotify | SpoolerYield
WrapStoreEntryID | Subscribe | Unsubscribe

Message service support objects have implementations for the following methods:

DoConfigPropsheet | GetLastError
GetMemAllocRoutines | GetSvcConfigSupportObj
MakeInvalid | NewUID
OpenProfileSection |


IMAPISupport::Address

The IMAPISupport::Address method displays the common address dialog box.

Quick Info

See IMAPISupport : IUnknown.

HRESULT Address(
  ULONG FAR * lpulUIParam,
  LPADRPARM lpAdrParms,
  LPADRLIST FAR * lppAdrList
);

Parameters

lpulUIParam
[in, out] Handle of the parent window of the dialog box. On input, a window handle must always be passed. On output, if the DIALOG_SDI flag is set in the ADRPARM structure pointed to by the lpAdrParms parameter, then the window handle of the modeless dialog box is returned.
lpAdrParms
[in, out] Pointer to an ADRPARM structure that controls the presentation and behavior of the address dialog box.
lppAdrList
[in, out] Pointer to a pointer to an address list. On input, this list is either the current list of recipients in a message or NULL, if no such list exists. On output, lppAdrList points to an updated list of message recipients.

Return Values

S_OK
The address dialog box was successfully displayed.

Remarks

The IMAPISupport::Address method is implemented for address book provider support objects. Address book providers call Address to create or update a list of message recipients.

Each recipient is described in an ADRENTRY structure that is included in the ADRLIST structure pointed to by lppAdrList. The ADRENTRY structure contains an array of recipient property values, one of which is the recipient's type, or PR_RECIPIENT_TYPE property. This ADRLIST structure can be passed to a client to use as the lpMods parameter in a call to IMessage::ModifyRecipients.

Each recipient in the ADRLIST structure can either be resolved, indicating that one of its property values is its PR_ENTRYID property, or unresolved, indicating that the PR_ENTRYID property is missing.

In addition to PR_ENTRYID, resolved recipients include the following properties:

PR_RECIPIENT_TYPE

PR_DISPLAY_NAME

PR_ADDRTYPE

PR_DISPLAY_TYPE

Unresolved recipients typically include only PR_DISPLAY_NAME and PR_RECIPIENT_TYPE.

Notes to Callers

The ADRLIST structure that the caller passes in might be a different size from the structure that MAPI returns. When allocating memory for the ADRLIST structure, allocate the memory for each SPropValue structure separately.

Use the pointers to the MAPI memory allocation functions passed in to your ABProviderInit function to allocate memory. Allocate memory for the ADRLIST structure and each property value structure within the ADRENTRY structures in the ADRLIST structure with the MAPIAllocateBuffer function.

If Address must return a larger ADRLIST structure, or if you have passed NULL for lppAdrList, it frees the original structure and allocates a new one. Address also allocates additional property value structures in the ADRLIST structure and frees old ones as appropriate. For more information about how memory is managed for ADRLIST structures, see Managing Memory for ADRLIST and SRowSet Structures.

Address returns immediately if the DIALOG_SDI flag was set in the ADRPARM structure in the lpAdrParms parameter.

See Also

ADRENTRY, ADRLIST, ADRPARM, FreePadrlist, FreeProws, IMAPISupport::GetMemAllocRoutines, IMAPITable::QueryRows, IMessage::ModifyRecipients, MAPIAllocateBuffer, MAPIAllocateMore, MAPIFreeBuffer, SPropValue, SRowSet


IMAPISupport::CompareEntryIDs

The IMAPISupport::CompareEntryIDs method compares two entry identifiers to determine if they refer to the same object.

Quick Info

See IMAPISupport : IUnknown.

HRESULT CompareEntryIDs(
  ULONG cbEntryID1,
  LPENTRYID lpEntryID1,
  ULONG cbEntryID2,
  LPENTRYID lpEntryID2,
  ULONG ulFlags,
  ULONG FAR * lpulResult
);

Parameters

cbEntryID1
[in] Count of bytes in the entry identifier pointed to by the lpEntryID1 parameter.
lpEntryID1
[in] Pointer to the first entry identifier to be compared.
cbEntryID2
[in] Count of bytes in the entry identifier pointed to by the lpEntryID2 parameter.
lpEntryID2
[in] Pointer to the second entry identifier to be compared.
ulFlags
Reserved; must be zero.
lpulResult
[out] Pointer to the result of the comparison, set toTRUE if the two entry identifiers refer to the same object and FALSE otherwise.

Return Values

S_OK
The comparison was successful.
MAPI_E_UNKNOWN_ENTRYID
One or both of the entry identifiers specified as parameters do not refer to valid objects, possibly because they are unopened and inaccessible at present.

Remarks

The IMAPISupport::CompareEntryIDs method is implemented for address book and message store provider support objects. CompareEntryIDs compares two entry identifiers belonging to a single service provider to determine whether they refer to the same object. MAPI extracts the MAPIUID portion from the entry identifiers to determine the service provider responsible for the objects and calls its logon object's CompareEntryIDs method to perform the comparison.

Notes to Callers

CompareEntryIDs is useful because an object can have more than one valid entry identifier; such a situation can occur, for example, after a new version of a service provider is installed.

If CompareEntryIDs returns an error, do not take any action based on the result of the comparison. Instead, take the most conservative approach possible. CompareEntryIDs might fail if, for example, one or both of the entry identifiers contains an invalid MAPIUID.


IMAPISupport::CompleteMsg

The IMAPISupport::CompleteMsg method performs postprocessing on a message.

Quick Info

See IMAPISupport : IUnknown.

HRESULT CompleteMsg(
  ULONG ulFlags,
  ULONG cbEntryID,
  LPENTRYID lpEntryID
);

Parameters

ulFlags
Reserved; must be zero.
cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the message to process.

Return Values

S_OK
The postprocessing was successful.

Remarks

The IMAPISupport::CompleteMsg method is implemented for message store provider support objects and is called only by message store providers that are tightly coupled with transport providers. Tightly coupled store providers call IMAPISupport::CompleteMsg to instruct the MAPI spooler to postprocess a message.

Notes to Callers

Call CompleteMsg only when you are tightly coupled with a transport provider, you can handle all of the message's recipients, and one of the following conditions exists:

  • The message in question was preprocessed.
  • The message in question requires postprocessing by the MAPI spooler, possibly causing messaging hook providers to be invoked.


IMAPISupport::CopyFolder

The IMAPISupport::CopyFolder method copies or moves a folder from its current parent folder to another parent folder.

Quick Info

See IMAPISupport : IUnknown.

HRESULT CopyFolder(
  LPCIID lpSrcInterface,
  LPVOID lpSrcFolder,
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  LPCIID lpInterface,
  LPVOID lpDestFolder,
  LPSTR lpszNewFolderName,
  ULONG ulUIParam,
  LPMAPIPROGRESS lpProgress,
  ULONG ulFlags
);

Parameters

lpSrcInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the parent folder of the folder to be copied or moved.
lpSrcFolder
[in] Pointer to the parent folder of the folder to be copied or moved.
cbEntryID
[in] Count of bytes in the entry identifier pointed to by lpEntryID.
lpEntryID
[in] Pointer to the entry identifier of the folder to be copied or moved.
lpInterface
Reserved; must be NULL.
lpDestFolder
[in] Pointer to the folder that is to receive the folder to be copied or moved.
lpszNewFolderName
[in] Pointer to the name of the copied or moved folder or NULL, indicating that the copied or moved folder should have the same name as the source folder, the folder pointed to by lpEntryID.
ulUIParam
[in] Handle of the window for the progress indicator dialog box and related windows. The ulUIParam parameter is ignored unless the FOLDER_DIALOG flag is set in the ulFlags parameter.
lpProgress
[in] Pointer to a progress object for displaying a progress indicator. If NULL is passed in lpProgress, the message store provider displays a progress indicator using the MAPI progress object implementation. The lpProgress parameter is ignored unless the FOLDER_DIALOG flag is set in ulFlags.
ulFlags
[in] Bitmask of flags that controls how the copy or move operation is accomplished. The following flags can be set:
COPY_SUBFOLDERS

All of the folder's subfolders should be copied or moved. When COPY_SUBFOLDERS is not set for a copy operation, only the folder identified by lpEntryID is copied. With a move operation, the COPY_SUBFOLDERS behavior is the default regardless of whether the flag is set.

FOLDER_DIALOG
Requests the display of a progress indicator.
FOLDER_MOVE
The folder should be moved rather than copied. If FOLDER_MOVE is not set, the folder is copied.
MAPI_UNICODE
The name of the folder is in Unicode format. If the MAPI_UNICODE flag is not set, the name of the folder is in ANSI format.

Return Values

S_OK
The folder has been successfully copied or moved.
MAPI_E_COLLISION

The name of the folder being moved or copied is the same as that of a subfolder in the destination folder. The message store provider requires that folder names be unique. The operation stops without completing.

MAPI_W_PARTIAL_COMPLETION

The call succeeded, but not all entries were successfully copied. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IMAPISupport::CopyFolder method is implemented for message store provider support objects. Message store providers can call CopyFolder in their implementation of IMAPIFolder::CopyFolder to copy or move a single folder from one parent folder to another.

CopyFolder adds the copied or moved folder as a subfolder of the destination folder.

Notes to Callers

CopyFolder allows simultaneous renaming and moving of folders and the copying or moving of subfolders of the affected folder. To copy or move all subfolders nested within the copied or moved folder, pass the COPY_SUBFOLDERS flag in ulFlags.

Expect these return values under the following conditions:

Condition | Return value
CopyFolder has successfully copied or moved the folder and all of its subfolders, if applicable. | S_OK
CopyFolder was unable to successfully copy or move all of the folders. | MAPI_W_PARTIAL_COMPLETION
CopyFolder was unable to complete. | Any error value

If CopyFolder returns an error value, do not proceed on the assumption that no work was done. One or more folders could have been copied or moved before CopyFolder experienced the failure.


IMAPISupport::CopyMessages

The IMAPISupport::CopyMessages method copies or moves messages from one folder to another folder.

Quick Info

See IMAPISupport : IUnknown.

HRESULT CopyMessages(
  LPCIID lpSrcInterface,
  LPVOID lpSrcFolder,
  LPENTRYLIST lpMsgList,
  LPCIID lpDestInterface,
  LPVOID lpDestFolder,
  ULONG ulUIParam,
  LPMAPIPROGRESS lpProgress,
  ULONG ulFlags
);

Parameters

lpSrcInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the folder containing the messages to be copied or moved.
lpSrcFolder
[in] Pointer to the folder containing the messages to be copied or moved.
lpMsgList
[in] Pointer to an array of entry identifiers identifying the messages to be copied or moved.
lpDestInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the destination folder for the copied or moved messages.
lpDestFolder
[in] Pointer to the destination folder for the copied or moved messages. This folder must be open.
ulUIParam
[in] Pointer to a progress object for displaying a progress indicator. If NULL is passed in lpProgress, the message store provider displays a progress indicator using the MAPI progress object implementation. The lpProgress parameter is ignored unless the MESSAGE_DIALOG flag is set in ulFlags.
lpProgress
[in] Pointer to a progress object for displaying a progress indicator. If NULL is passed in lpProgress, the message store provider displays a progress indicator using the MAPI progress object implementation. The lpProgress parameter is ignored unless the MESSAGE_DIALOG flag is set in ulFlags.
ulFlags
[in] Bitmask of flags that controls how the copy or move operation is accomplished. The following flags can be set:
MESSAGE_DIALOG
Requests the display of a progress indicator.
MESSAGE_MOVE
The messages should be moved, rather than copied. If MESSAGE_MOVE is not set, the messages are copied.

Return Values

S_OK
The copy or move operation was successful.
MAPI_E_USER_CANCEL
The user canceled the operation, typically by clicking the Cancel button in a dialog box.

Remarks

The IMAPISupport::CopyMessages method is implemented for message store provider support objects. Message store providers can call CopyMessages in their implementation of IMAPIFolder::CopyMessages to copy or move one or more messages from one folder to another. As part of the CopyMessages call, the message store provider can specify that MAPI display a progress indicator.


IMAPISupport::CreateOneOff

The IMAPISupport::CreateOneOff method creates an entry identifier for a one-off address.

Quick Info

See IMAPISupport : IUnknown.

HRESULT CreateOneOff(
  LPTSTR lpszName,
  LPTSTR lpszAdrType,
  LPTSTR lpszAddress,
  ULONG ulFlags,
  ULONG FAR * lpcbEntryID,
  LPENTRYID FAR * lppEntryID
);

Parameters

lpszName
[in] Pointer to the display name of the recipient — the PR_DISPLAY_NAME property. The lpszName parameter can be NULL.
lpszAdrType
[in] Pointer to the address type of the recipient, such as FAX, SMTP, or X500. The lpszAdrType parameter cannot be NULL.
lpszAddress
[in] Pointer to the messaging address of the recipient. The lpszAddress parameter cannot be NULL.
ulFlags
[in] Bitmask of flags that affects the one-off recipient. The following flags can be set:
MAPI_SEND_NO_RICH_INFO
The recipient cannot handle formatted message content. If MAPI_SEND_NO_RICH_INFO is set, MAPI sets the recipient's PR_SEND_RICH_INFO property to FALSE. If MAPI_SEND_NO_RICH_INFO is not set, MAPI sets this property to TRUE unless the recipient's messaging address pointed to by lpszAddress is interpreted to be an Internet address. In this case, MAPI sets PR_SEND_RICH_INFO to FALSE.
MAPI_UNICODE
The display name, address type, and address are in Unicode format. If the MAPI_UNICODE flag is not set, these strings are in ANSI format.
lpcbEntryID
[out] Pointer to the count of bytes in the entry identifier pointed to by the lppEntryID parameter.
lppEntryID
[out] Pointer to a pointer to the entry identifier for the one-off recipient.

Return Values

S_OK
The one-off entry identifier was successfully created.

Remarks

The IMAPISupport::CreateOneOff method is implemented for all service provider support objects. Service providers call CreateOneOff to create an entry identifier for a one-off recipient — a recipient that does not belong to any of the containers from any of the currently loaded address book providers.

Notes to Callers

When finished using the entry identifier returned by CreateOneOff, free the memory allocated for the entry identifier by using the MAPIFreeBuffer function.

Notes to Transport Providers

Support the Transport Neutral Encapsulation Format, or TNEF, and use the value of the PR_SEND_RICH_INFO property to determine whether or not to use TNEF when transporting a message. Not supporting TNEF or not sending a message in this format when requested can be a problem for form-based clients or clients that require custom MAPI properties. This is because TNEF is typically used to send custom properties for custom message classes.

See Also

MAPIFreeBuffer


IMAPISupport::Details

The IMAPISupport::Details method displays a modal dialog box showing details about a particular address book entry.

Quick Info

See IMAPISupport : IUnknown.

HRESULT Details(
  ULONG FAR * lpulUIParam,
  LPFNDISMISS lpfnDismiss,
  LPVOID lpvDismissContext,
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  LPFNBUTTON lpfButtonCallback,
  LPVOID lpvButtonContext,
  LPTSTR lpszButtonText,
  ULONG ulFlags
);

Parameters

lpulUIParam
[out] Handle of the parent window for the returned dialog box.
lpfnDismiss
[in] Pointer to a function based on the DISMISSMODELESS function prototype. This function is called when the modeless variety of the details dialog box is dismissed. This parameter is ignored at present because MAPI does not support a modeless details dialog box.
lpvDismissContext
[in] Data that is passed to the function specified by the lpfnDismiss parameter. This parameter is currently ignored.
cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier for which details are displayed.
lpfButtonCallback

[in] Pointer to a function based on the LPFNBUTTON function prototype. An LPFNBUTTON function adds a button to the details dialog box.

lpvButtonContext
[in] Pointer to data used as a parameter for the function specified by the lpfButtonCallback parameter.
lpszButtonText

[in] Pointer to a string containing text to be applied to the added button if that button is extensible. The lpszButtonText parameter should be NULL if an extensible button is not needed.

ulFlags
[in] Bitmask of flags that controls the type of the text for the lpszButtonText parameter. The following flag can be set:
MAPI_UNICODE
The passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.

Return Values

S_OK
The details dialog box was successfully displayed for the address book entry.

Remarks

The IMAPISupport::Details method is implemented for address book provider support objects. Address book providers call Details to display a modal dialog box giving details on a particular entry in the address book. The lpfButtonCallback, lpvButtonContext, and lpButtonText parameters can be used to add a button the client has defined to the dialog box. When the button is clicked, MAPI calls the callback function pointed to by lpfButtonCallback, passing both the entry identifier of the button and the data in lpvButtonContext. If an extensible button is not needed, lpszButtonText should be NULL.

See Also

IMAPISupport::Address, LPFNBUTTON


IMAPISupport::DoConfigPropsheet

The IMAPISupport::DoConfigPropsheet method displays a configuration property sheet.

Quick Info

See IMAPISupport : IUnknown.

HRESULT DoConfigPropsheet(
  ULONG ulUIParam,
  ULONG ulFlags,
  LPTSTR lpszTitle,
  LPMAPITABLE lpDisplayTable,
  LPMAPIPROP lpConfigData,
  ULONG ulTopPage
);

Parameters

ulUIParam
[in] Handle of the parent window for the property sheet.
ulFlags
Reserved; must be zero.
lpszTitle
[in] Pointer to the title of the property sheet.
lpDisplayTable
[in] Pointer to the display table that describes the controls to appear on the property sheet.
lpConfigData
[in] Pointer to the IMAPIProp implementation to be used for accessing the configuration properties to be displayed on the property sheet.
ulTopPage
[in] A zero-based index to the default top page of the property sheet.

Return Values

S_OK
The configuration property sheet was displayed.

Remarks

The IMAPISupport::DoConfigPropSheet method is implemented for all support objects. DoConfigPropSheet provides a standard user interface for displaying the properties of service providers and message services. Microsoft strongly recommends that this standard dialog box be used for all configuration property displays so that users benefit from a consistent Windows interface.

Service providers call DoConfigPropSheet as part of their implementation of the IMAPIStatus::SettingsDialog method or from a button used to display details on properties. Message services call DoConfigPropSheet from their message service entry point function.

Notes to Callers

You can create the display table pointed to by the lpDisplayTable parameter by calling the BuildDisplayTable function or with custom code.

See Also

BuildDisplayTable, CreateIProp, IABProvider::Logon, IMAPIProp : IUnknown, IMAPIStatus::SettingsDialog, IMsgServiceAdmin : IUnknown, IMSProvider::Logon, IXPProvider::TransportLogon


IMAPISupport::DoCopyProps

The IMAPISupport::DoCopyProps method copies or moves one or more properties of an object to another object.

Quick Info

See IMAPISupport : IUnknown.

HRESULT DoCopyProps(
  LPCIID lpSrcInterface,
  LPVOID lpSrcObj,
  LPSPropTagArray lpIncludeProps,
  ULONG ulUIParam,
  LPMAPIPROGRESS lpProgress,
  LPCIID lpDestInterface,
  LPVOID lpDestObj,
  ULONG ulFlags,
  LPSPropProblemArray FAR * lppProblems
);

Parameters

lpSrcInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the object with the properties to be copied or moved.
lpSrcObj
[in] Pointer to the object with the properties to be copied or moved.
lpIncludeProps
[in] Pointer to an SPropTagArray structure holding a counted array of property tags indicating the properties to copy or move. The lpIncludeProps parameter cannot be NULL.
ulUIParam
[in] Handle of the parent window for the progress indicator.
lpProgress

[in] Pointer to an implementation of a progress indicator. If NULL is passed in the lpProgress parameter, the progress indicator is displayed using the MAPI implementation. The lpProgress parameter is ignored unless the MAPI_DIALOG flag is set in the ulFlags parameter.

lpDestInterface
[in] Pointer to the interface identifier representing the interface to be used to access the object to receive the properties that are copied or moved.
lpDestObj
[in] Pointer to the object to receive the copied or moved properties.
ulFlags
[in] Bitmask of flags that controls how the copy or move operation is performed. The following flags can be set:
MAPI_DIALOG
Allows the display of a progress indicator.
MAPI_MOVE

DoCopyProps should perform a move operation rather than a copy operation. When this flag is not set, DoCopyProps performs a copy operation.

MAPI_NOREPLACE
Existing properties in the destination object should not be overwritten. When this flag is not set, DoCopyProps overwrites existing properties.
lppProblems

[in, out] On input, can be NULL, indicating no need for error information, or a pointer to a pointer to an SPropProblemArray structure. If lppProblems is a valid pointer on input, DoCopyProps returns detailed information about errors in copying one or more properties.

Return Values

S_OK
Properties have been successfully copied or moved.
MAPI_E_COLLISION
A property to be copied or moved already exists in the destination object and the MAPI_NOREPLACE flag is set.
MAPI_E_FOLDER_CYCLE
The source object directly or indirectly contains the destination object. Significant work might have been performed before this condition was discovered, so the source and destination objects might be partially modified.
MAPI_E_INTERFACE_NOT_SUPPORTED

The interface identified by the lpSrcInterface parameter is not supported by the source object or the interface identified by the lpDestInterface parameter is not supported by the destination object.

MAPI_E_NO_ACCESS

An attempt was made to access an object for which the caller has insufficient permissions. This error is returned if the destination object is the same as the source object.

The following values can be returned in the SPropProblemArray structure, but not as return values for DoCopyProps. These errors apply to a single property:

MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and DoCopyProps does not support Unicode, or MAPI_UNICODE was not set and DoCopyProps only supports Unicode.
MAPI_E_COMPUTED

The property cannot be modified by the caller because it is a read-only property, computed by the owner of the destination object. This error is not severe; the caller should allow the copy operation to continue.

MAPI_E_INVALID_TYPE
The property type is invalid.
MAPI_E_UNEXPECTED_TYPE
The property type is not the type expected by the caller.

Remarks

The IMAPISupport::DoCopyProps method is implemented for message store provider support objects. Message store providers can call DoCopyProps to implement IMAPIProp::CopyProps for their folders and messages. IMAPISupport::DoCopyProps copies or moves the properties identified in the property tag array pointed to by lpIncludeProps that are present in the object pointed to by lpSrcObj.

Notes to Callers

When copying properties between like objects, such as between two messages, the lpSrcInterface and lpDestInterface parameters must contain the same interface identifier and the lpSrcObj and lpDestObj parameters must point to objects of the same type. If lpDestInterface is set to NULL, then DoCopyProps returns MAPI_E_INVALID_PARAMETER. If you set lpDestInterface to an acceptable interface identifier, but set lpDestObj to an invalid pointer, the results are unpredictable. Most likely your provider will fail.

Set the MAPI_NOREPLACE flag if you do not want any of the properties in the destination object to be overwritten. Properties in the destination object that exist in the source object and are not overwritten are not deleted or modified.

To copy a message's recipient list, include the PR_MESSAGE_RECIPIENTS property in the property tag array pointed to by lpIncludeProps. To copy the message's attachments, include the PR_MESSAGE_ATTACHMENTS property.

To copy a folder or address book container's hierarchy or contents table, include PR_CONTAINER_HIERARCHY or PR_CONTAINER_CONTENTS in the property tag array. To include a folder's associated contents table, include the PR_FOLDER_ASSOCIATED_CONTENTS property in the array.

If subfolders are copied or moved, their contents are copied or moved in their entirety, regardless of the use of properties indicated by the SPropTagArray structure.

DoCopyProps reports global errors — errors that occur with the operation as a whole — and individual errors — errors that occur with one or more of the properties. These individual errors are placed in an SPropProblemArray structure. You can suppress error reporting at the property level by passing NULL for the property problem array structure parameter rather than a valid pointer.

If you want to receive information about errors, pass a valid SPropProblemArray structure pointer in the lppProblems parameter. When DoCopyProps returns S_OK, check for possible errors with individual properties in the structure. When DoCopyProps returns an error, no information is returned in the SPropProblemArray structure. Instead, call IMAPISupport::GetLastError to retrieve detailed error information.

If DoCopyProps returns S_OK, free the returned SPropProblemArray structure by calling the MAPIFreeBuffer function.

See Also

IMAPISupport::CopyMessages, IMAPISupport::DoCopyProps, IMAPISupport::DoCopyTo, SPropProblemArray, SPropTagArray


IMAPISupport::DoCopyTo

The IMAPISupport::DoCopyTo method copies or moves all properties of one object, except for specifically excluded properties, to another object.

Quick Info

See IMAPISupport : IUnknown.

HRESULT DoCopyTo(
  LPCIID lpSrcInterface,
  LPVOID lpSrcObj,
  ULONG ciidExclude,
  LPCIID rgiidExclude,
  LPSPropTagArray lpExcludeProps,
  ULONG ulUIParam,
  LPMAPIPROGRESS lpProgress,
  LPCIID lpDestInterface,
  LPVOID lpDestObj,
  ULONG ulFlags,
  LPSPropProblemArray FAR * lppProblems
);

Parameters

lpSrcInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the object with the properties to be copied or moved.
lpSrcObj
[in] Pointer to the object with the properties to be copied or moved.
ciidExclude
[in] Count of interfaces to exclude when copying or moving properties.
rgiidExclude
[in] Array of interface identifiers indicating interfaces that should not be used when copying or moving supplemental information to the destination object.
lpExcludeProps

[in] Pointer to a property tag array identifying the property tags that should be excluded from the copy or move operation. Passing NULL in the lpExcludeProps parameter indicates that all of the object's properties should be copied or moved. DoCopyTo returns MAPI_E_INVALID_PARAMETER when the cValues member of the SPropTagArray structure pointed to by lpExcludeProps is set to zero.

ulUIParam
[in] Handle of the parent window for the progress indicator.
lpProgress

[in] Pointer to a progress indicator implementation. If NULL is passed in the lpProgress parameter, MAPI provides the progress implementation. The lpProgress parameter is ignored unless the MAPI_DIALOG flag is set in the ulFlags parameter.

lpDestInterface
[in] Pointer to the interface identifier representing the interface to be used to access the object to receive the copied or moved properties.
lpDestObj
[in] Pointer to the object to receive the copied or moved properties.
ulFlags
[in] Bitmask of flags that controls the copy or move operation. The following flags can be set:
MAPI_DIALOG
Allows the display of a progress indicator.
MAPI_MOVE

DoCopyTo should perform a move operation rather than a copy operation. When this flag is not set, DoCopyTo performs a copy operation.

MAPI_NOREPLACE
Existing properties in the destination object should not be overwritten. When this flag is not set, DoCopyTo overwrites existing properties.
lppProblems

[out] On input, can be NULL, indicating no need for error information, or a pointer to a pointer to an SPropProblemArray structure. If lppProblems is a valid pointer on input, DoCopyTo returns detailed information about errors in copying one or more properties.

Return Values

S_OK
The properties have been successfully copied or moved.
MAPI_E_COLLISION
A property to be copied or moved already exists in the destination object and the MAPI_NOREPLACE flag is set.
MAPI_E_FOLDER_CYCLE
The source object directly or indirectly contains the destination object. Significant work might have been performed before this condition was discovered, so the source and destination objects might be partially modified.
MAPI_E_INTERFACE_NOT_SUPPORTED

The interface identified by the lpSrcInterface parameter is not supported by the object pointed to by lpSrcObj, or the interface identified by the lpDestInterface parameter is not supported by the object pointed to by lpDestObj.

MAPI_E_NO_ACCESS

An attempt was made to access an object for which the caller has insufficient permissions. This error is returned if the destination object is the same as the source object.

MAPI_E_INVALID_PARAMETER

The lpSrcInterface parameter is NULL.

The following values can be returned in the SPropProblemArray structure, but not as return values for DoCopyTo. These errors apply to a single property:

MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and DoCopyTo does not support Unicode, or MAPI_UNICODE was not set and DoCopyTo only supports Unicode.
MAPI_E_COMPUTED

The property cannot be modified by the caller because it is a read-only property, computed by the owner of the destination object. This error is not severe; the caller should allow the copy operation to continue.

MAPI_E_INVALID_TYPE
The property type is invalid.
MAPI_E_UNEXPECTED_TYPE
The property type is not the type expected by the caller.

Remarks

The IMAPISupport::DoCopyTo method is implemented for message store provider support objects. Message store providers can call DoCopyTo to implement IMAPIProp::CopyTo for their folders and messages.

By default, DoCopyTo copies or moves all of the properties of one object to another object. Any subobjects in the source object are automatically included in the operation and copied or moved in their entirety.

If any of the copied or moved properties already exist in the destination object, the existing properties are overwritten by the new, unless the MAPI_NOREPLACE flag is set in the ulFlags parameter. Existing information in the destination object that is not overwritten is left untouched.

Notes to Callers

To exclude properties from the copy or move operation, include their property tags in the lpExcludeProps parameter. If you pass the results of using the PROP_TAG macro to build a property tag from a specific identifier in the property tag array, all properties with that identifier will be excluded. For example, the following entry in the property tag array causes all properties with an identifier of 0x8002 to be excluded, regardless of type:

PROP_TAG(PT_LONG, 0x8002)

To avoid copying a message's delivery time when copying the message to a different folder, specify PR_MESSAGE_DELIVERY_TIME in the property tag exclude array. To exclude a message's recipient list, add the PR_MESSAGE_RECIPIENTS property to the exclude array. To exclude a message's attachments, add the PR_MESSAGE_ATTACHMENTS property to the array.

Similarly, prevent the copying or moving of a folder or address book container's hierarchy or contents table by including PR_CONTAINER_HIERARCHY or PR_CONTAINER_CONTENTS in the property tag exclude array.

Ignore MAPI_E_COMPUTED errors returned in the SPropProblemArray structure in the lppProblems parameter.

The interface identifier pointed to by lpSrcInterface is usually the same as the interface identifier pointed to by lpDestInterface.

If you pass an acceptable interface identifier in lpDestInterface but an invalid pointer in lpDestObj, the results are unpredictable. Most likely this will cause your provider to fail.

Conversely, if you are aware of supplemental information that should not be copied or moved, include the interface identifiers for the interfaces to be excluded in the array passed in the rgiidExclude parameter. For example, if you are copying messages, but not any of their message attachments, pass IID_IMessage in the rgiidExclude array. DoCopyTo ignores any interfaces listed in rgiidExclude it doesn't recognize.

When you use the rgiidExclude parameter to exclude an interface, it also excludes all interfaces derived from that interface. For example, excluding IMAPIContainer causes folders or address book containers to be excluded, depending on the type of provider. Do not exclude IMAPIProp or IUnknown because so many interfaces derive from them.

DoCopyTo reports global errors — errors that apply to the operation as a whole — and individual errors — errors that apply to individual properties. These individual errors are placed in an SPropProblemArray structure. You can suppress error reporting at the property level by passing NULL for the property problem array structure parameter rather than a valid pointer.

If you want to receive information about errors, pass a valid SPropProblemArray structure pointer in the lppProblems parameter. When DoCopyTo returns S_OK, check for possible errors with individual properties in the structure. When DoCopyTo returns an error, no information is returned in the SPropProblemArray structure. Instead, call IMAPISupport::GetLastError to retrieve detailed error information.

If CopyTo returns S_OK, free the returned SPropProblemArray structure by calling the MAPIFreeBuffer function.

If a global error occurs on the DoCopyTo call, do not use or free the SPropProblemArray structure. Providers should ignore the ulIndex member in SPropProblemArray structures returned by DoCopyTo.

See Also

IMAPISupport::CopyFolder, IMAPISupport::CopyMessages, IMAPISupport::DoCopyTo, SPropProblemArray, SPropTagArray


IMAPISupport::DoProgressDialog

The IMAPISupport::DoProgressDialog method retrieves a progress object for displaying a progress indicator.

Quick Info

See IMAPISupport : IUnknown.

HRESULT DoProgressDialog(
  ULONG ulUIParam,
  ULONG ulFlags,
  LPMAPIPROGRESS FAR * lppProgress
);

Parameters

ulUIParam
[in] Handle of the parent window for the progress indicator.
ulFlags
[in] Bitmask of flags that controls how the progress object should calculate progress. The following flag can be set:
MAPI_TOP_LEVEL
Progress is being calculated for a top-level item, such as a parent folder. The progress object should use the values in the IMAPIProgress::Progress method's ulCount and ulTotal parameters — which indicate the item being operated on and the total items to operate on respectively — to increment progress made on the operation.
lppProgress
[out] Pointer to a pointer to the progress object.

Return Values

S_OK
The progress object was successfully retrieved.

Remarks

The IMAPISupport::DoProgressDialog method is implemented for address book and message store provider support objects. These providers call DoProgressDialog to access the MAPI implementation of the IMAPIProgress interface which calculates the progress information and displays the result in a standard dialog box.

For information about how to use a progress object and the IMAPIProgress interface, see Displaying Progress Step by Step.

See Also

IMAPIProgress : IUnknown


IMAPISupport::DoSentMail

The IMAPISupport::DoSentMail method performs processing on a sent message.

Quick Info

See IMAPISupport : IUnknown.

HRESULT DoSentMail(
  ULONG ulFlags,
  LPMESSAGE lpMessage
);

Parameters

ulFlags
Reserved; must be zero.
lpMessage
[in] Pointer to the open message for which a message should be generated in the folder designated to hold sent items.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

The IMAPISupport::DoSentMail method is implemented for message store provider support objects. Message store providers call DoSentMail from within their implementation of the IMsgStore::FinishedMsg method, called by the MAPI spooler when it has finished processing a message. FinishedMsg unlocks the message, ensures that the message's reference count is one, and calls IMAPISupport::DoSentMail.

DoSentMail performs the following tasks:

  • Determines whether the message should be deleted after sending by checking the message for the PR_DELETE_AFTER_SUBMIT property.
  • Determines the location of the Sent Items folder.
  • Initiates message hook processing for any hooks set on the Sent Items folder.
  • Moves the message to the Sent Items folder, Deleted Items folder, or to another folder as specified by any messaging hook providers.
  • Releases the message.

See Also

IMsgStore::FinishedMsg


IMAPISupport::ExpandRecips

The IMAPISupport::ExpandRecips method completes a message's recipient list, expanding particular distribution lists.

Quick Info

See IMAPISupport : IUnknown.

HRESULT ExpandRecips(
  LPMESSAGE lpMessage,
  ULONG FAR * lpulFlags
);

Parameters

lpMessage
[in] Pointer to the message with the recipient list to be processed.
lpulFlags
[out] Pointer to a bitmask of flags that controls the type of processing that occurs. The following flags can be set:
NEEDS_PREPROCESSING
The message needs to be preprocessed before it is sent.
NEEDS_SPOOLER
The MAPI spooler must send the message rather than the transport provider to which the caller is tightly coupled.

Return Values

S_OK
The message's recipient list was successfully processed.

Remarks

The IMAPISupport::ExpandRecips method is implemented for message store provider support objects. Message store providers call ExpandRecips to prompt MAPI to perform the following tasks:

  • Expand certain personal distribution lists to their component recipients.
  • Replace all display names that have been altered with the original names.
  • Mark any duplicate entries.
  • Resolve all one-off addresses.
  • Check if the message needs preprocessing and, if it does, set the flag pointed to by lpulFlags to NEEDS_PREPROCESSING.

ExpandRecips expands any distribution lists that have the messaging address type of MAPIPDL.

Notes to Callers

Always call ExpandRecips as part of your message processing. Make a call to ExpandRecips one of the first calls in your IMessage::SubmitMessage implementation.

See Also

IMessage::SubmitMessage


IMAPISupport::GetLastError

The IMAPISupport::GetLastError method returns a MAPIERROR structure containing information about the previous support object error.

Quick Info

See IMAPISupport : IUnknown.

HRESULT GetLastError(
  HRESULT hResult,
  ULONG ulFlags,
  LPMAPIERROR FAR * lppMAPIError
);

Parameters

hResult
[in] HRESULT data type containing the error value generated in the previous method call for the support object.
ulFlags
[in] Bitmask of flags that controls the type of the returned strings. The following flag can be set:
MAPI_UNICODE
The strings in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppMAPIError
[out] Pointer to a pointer to the MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if a MAPIERROR structure with appropriate error information cannot be provided.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and MAPI does not support Unicode, or MAPI_UNICODE was not set and MAPI only supports Unicode.

Remarks

The IMAPISupport::GetLastError method is implemented for all support objects. Callers can provide their users with detailed information about the error by including the data from the MAPIERROR structure in a dialog box.

Notes to Callers

You can make use of the MAPIERROR structure pointed to by the lppMAPIError parameter, if MAPI supplies one, only if GetLastError returns S_OK. Sometimes MAPI cannot determine what the last error was or has nothing more to report about the error. In this situation, a pointer to NULL is returned in lppMAPIError instead.

For more information about the GetLastError method, see Using Extended Errors.

To release all the memory allocated by MAPI, call the MAPIFreeBuffer function for the returned MAPIERROR structure.

See Also

MAPIERROR, MAPIFreeBuffer


IMAPISupport::GetMemAllocRoutines

The IMAPISupport::GetMemAllocRoutines method retrieves the addresses of the MAPI memory allocation and deallocation functions: MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer.

Quick Info

See IMAPISupport : IUnknown.

HRESULT GetMemAllocRoutines(
  LPALLOCATEBUFFER FAR * lppAllocateBuffer,
  LPALLOCATEMORE FAR * lppAllocateMore,
  LPFREEBUFFER FAR * lppFreeBuffer
);

Parameters

lppAllocateBuffer
[out] Pointer to a pointer to the MAPIAllocateBuffer function. The MAPIAllocateBuffer function allocates memory.
lppAllocateMore
[out] Pointer to a pointer to the MAPIAllocateMore function. The MAPIAllocateMore function allocates additional memory for memory originally allocated with MAPIAllocateBuffer.
lppFreeBuffer
[out] Pointer to a pointer to the MAPIFreeBuffer function. The MAPIFreeBuffer function frees memory.

Return Values

S_OK
The function addresses were successfully returned.

Remarks

The IMAPISupport::GetMemAllocRoutines method is implemented for all support objects. Service providers call GetMemAllocRoutines to get the addresses of the three memory allocation functions passed to their initialization function: ABProviderInit, MSProviderInit, or XPProviderInit.

See Also

MAPIAllocateBuffer, MAPIAllocateMore, MAPIFreeBuffer


IMAPISupport::GetOneOffTable

The IMAPISupport::GetOneOffTable method returns a pointer to the MAPI one-off table — a list of templates supported by all address book providers for creating new recipients.

Quick Info

See IMAPISupport : IUnknown.

HRESULT GetOneOffTable(
  ULONG ulFlags,
  LPMAPITABLE FAR * lppTable
);

Parameters

ulFlags
[in] Bitmask of flags that controls the type of the string columns. The following flag can be set:
MAPI_UNICODE
The string columns are in Unicode format. If the MAPI_UNICODE flag is not set, the string columns are in ANSI format.
lppTable
[out] Pointer to a pointer to the one-off table.

Return Values

S_OK
The one-off table was successfully retrieved.

Remarks

The IMAPISupport::GetOneOffTable method is implemented for address book provider support objects. Address book providers call GetOneOffTable to retrieve the complete list of templates for creating new recipients. Included in this table are templates supported by all of the address book providers active in the session as well as templates supported by MAPI.

The newly created recipients can be used to address a message or added to an address book container.

For a list of the properties that make up the required column set in one-off tables, see One-Off Tables.

Setting the MAPI_UNICODE flag in the ulFlags parameter affects the format of the columns returned from the following IMAPITable methods:

IMAPITable::QueryColumns

IMAPITable::QueryRows

This flag also controls the property types in the sort order returned by the IMAPITable::QuerySortOrder method.

Notes to Callers

If registered for notification of changes to this one-off table, you will also receive notifications of changes made to other providers' one-off tables. Based on these notifications, you can support new address types that are added during the current session.

See Also

IABContainer::CreateEntry, IMAPISupport::NewEntry, PR_CREATE_TEMPLATES


IMAPISupport::GetSvcConfigSupportObj

The IMAPISupport::GetSvcConfigSupportObj method creates a message service support object.

Quick Info

See IMAPISupport : IUnknown.

HRESULT GetSvcConfigSupportObj(
  ULONG ulFlags,
  LPMAPISUP FAR * lppSvcSupport
);

Parameters

ulFlags
Reserved; must be zero.
lppSvcSupport
[out] Pointer to a pointer to the new message service support object.

Return Values

S_OK
The configuration support object was successfully created.

Remarks

The IMAPISupport::GetSvcConfigSupportObj method is implemented for all support objects. Service providers call GetSvcConfigSupportObj to create a configuration support object to pass to a message service entry point function.

A message service entry point function is based on the MSGSERVICEENTRY prototype and is called by methods of the IMsgServiceAdmin interface. A message service entry point function allows message services to configure themselves or perform other actions when the profile is changed. Message service entry point functions can support configuration changes by displaying a property sheet or through a property value array passed to the IMsgServiceAdmin::ConfigureMsgService method.

See Also

IMsgServiceAdmin::CreateMsgService, IProfAdmin : IUnknown, MSGSERVICEENTRY


IMAPISupport::IStorageFromStream

The IMAPISupport::IStorageFromStream method implements a storage object to access a stream.

Quick Info

See IMAPISupport : IUnknown.

HRESULT IStorageFromStream(
  LPUNKNOWN lpUnkIn,
  LPCIID lpInterface,
  ULONG ulFlags,
  LPSTORAGE FAR * lppStorageOut
);

Parameters

lpUnkIn
[in] Pointer to a stream object.
lpInterface
[in] Pointer to the interface identifier (IID) that represents the interface to be used to access the stream pointed to by lpUnkIn. Any of the following values are valid: NULL, indicating that IStream should be used to access the stream, IID_IStream, or IID_ILockBytes.
ulFlags
[in] Bitmask of flags that controls how the storage object is to be created relative to the stream object. By default, the storage is created with read-only access and the stream starts at position zero within the storage. The following flags can be set:
STGSTRM_CREATE
A new storage object should be created for the stream object.
STGSTRM_CURRENT
The storage object should start at the current position of the stream.
STGSTRM_MODIFY
The caller should have read/write access to the returned storage object.
STGSTRM_RESET
The storage object should start at position zero.
lppStorageOut
[out] Pointer to a pointer to the storage object.

Return Values

S_OK
The storage object was successfully created.

Remarks

The IMAPISupport::IStorageFromStream method is implemented for all service provider support objects. Service providers call IStorageFromStream to create a storage object to use for opening particular properties. Service providers that have their own implementation of IStorage do not need to call IStorageFromStream.

The storage object created by IStorageFromStream calls the stream's IUnknown::AddRef method to increment its reference count and then decrements the count when the storage is released.

Notes to Callers

When the IMAPIProp::OpenProperty method of one of your objects is called to open a property with the IStorage interface, perform the following tasks:

  1. Open a stream object with read/write access for the property.
  2. Internally mark the property stream as a storage object.
  3. Call IStorageFromStream to generate a storage object.
    1. Return a pointer to this storage object.

If you implement additional interfaces that use the storage object, create an object that wraps the storage object and implement a higher level IUnknown::QueryInterface method.

Do not allow a property to be opened with the IStream interface if it was created with IStorage. Conversely, do not allow a property to be opened with the IStorage interface if it was created with IStream.

With one exception, it is acceptable to use the IStreamDocfile interface to stream a storage object from one container to another, but the IID_IStreamDocfile interface identifier must be passed in the OpenProperty method's lpInterface parameter.

See Also

IMAPIProp::OpenProperty


IMAPISupport::MakeInvalid

The IMAPISupport::MakeInvalid method marks an object as unusable.

Quick Info

See IMAPISupport : IUnknown.

HRESULT MakeInvalid(
  ULONG ulFlags,
  LPVOID lpObject,
  ULONG ulRefCount,
  ULONG cMethods
);

Parameters

ulFlags
Reserved; must be zero.
lpObject
[in] Pointer to the object to be invalidated. The object's interface must be derived from IUnknown.
ulRefCount
[in] The object's present reference count.
cMethods
[in] Count of methods in the object's vtable.

Return Values

S_OK
The object was successfully marked as unusable.

Remarks

The IMAPISupport::MakeInvalid method is implemented for all support objects. The object to be invalidated must be derived from the IUnknown interface or from an interface derived from IUnknown.

MakeInvalid marks an object as unusable by replacing the object's vtable with a stub vtable of similar size in which the IUnknown::AddRef and IUnknown::Release methods perform as expected but any other methods fail, returning the value MAPI_E_INVALID_OBJECT.

Notes to Callers

Service providers and message services typically call IMAPISupport::MakeInvalid at shutdown time. However, MakeInvalid can be called at any time. For example, if a client releases an object without releasing some of its subobjects, you can call MakeInvalid immediately to release those subobjects.

You must own the object that you attempt to invalidate. It must be at least 16 bytes long and have at least three methods in its vtable.

You can call MakeInvalid and then perform any shutdown work, such as discarding associated data structures, that is usually done during the release of an object. Code to support the object need not be kept in memory because MAPI frees the memory by calling MAPIFreeBuffer and then releases the object. You can release resources, call MakeInvalid, and then ignore the invalidated object.

See Also

MAPIAllocateBuffer


IMAPISupport::ModifyProfile

The IMAPISupport::ModifyProfile method makes changes to a message store profile section permanent.

Quick Info

See IMAPISupport : IUnknown.

HRESULT ModifyProfile(
  ULONG ulFlags
);

Parameters

ulFlags
[in] Bitmask of flags that indicates the type of message store. The following flag can be set:
MDB_TEMPORARY
The message store is temporary and should not be added to the message store table. When MDB_TEMPORARY is set, ModifyProfile returns S_OK immediately.

Return Values

S_OK
The changes to the profile section were successful.

Remarks

The IMAPISupport::ModifyProfile method is implemented for message store provider support objects. Message store providers call ModifyProfile to prompt MAPI to modify their profile information.

ModifyProfile adds the profile section associated with the calling provider to the list of installed message store provider resources. This causes the message store to be listed in the message store table, available to clients through the IMAPISession::GetMsgStoresTable method, and to be opened without the display of a dialog box.

If the MDB_TEMPORARY flag is set, MAPI does nothing and the method returns immediately with S_OK.

See Also

IMAPISession::GetMsgStoresTable


IMAPISupport::ModifyStatusRow

The IMAPISupport::ModifyStatusRow method modifies the status table by adding a new row or modifying an existing row.

Quick Info

See IMAPISupport : IUnknown.

HRESULT ModifyStatusRow(
  ULONG cValues,
  LPSPropValue lpColumnVals,
  ULONG ulFlags
);

Parameters

cValues
[in] Count of properties to be included in the new or modified status table row.
lpColumnVals
[in] Pointer to an array of property values describing the properties to be included as columns in the new or modified status table row.
ulFlags
[in] Bitmask of flags that controls how information defining the status table row is processed. The following flag can be set:
STATUSROW_UPDATE
Directs MAPI to merge the properties included in the array pointed to by lpColumnVals with an existing status table row rather than add them in a new row.

Return Values

S_OK
The status table was successfully updated.

Remarks

The IMAPISupport::ModifyStatusRow method is implemented for all service provider support objects. Service providers call ModifyStatusRow at logon time to add a row to the status table and at other times during the session to update the row. ModifyStatusRow provides MAPI with the information necessary to build the status table.

Notes to Callers

Set the STATUSROW_UPDATE flag when you call ModifyStatusRow to make changes to the properties in your existing status table row. Doing so informs MAPI that only the columns being changed are passed in the lpColumnVals parameter.

Clients can use the information in the status table to access your status object.

For a complete list of columns that you should include in your status table row, see Status Table.


IMAPISupport::NewEntry

The IMAPISupport::NewEntry adds a new recipient directly to an address book container or to the recipient list of an outgoing message.

Quick Info

See IMAPISupport : IUnknown.

HRESULT NewEntry(
  ULONG ulUIParam,
  ULONG ulFlags,
  ULONG cbEIDContainer,
  LPENTRYID lpEIDContainer,
  ULONG cbEIDNewEntryTpl,
  LPENTRYID lpEIDNewEntryTpl,
  ULONG FAR * lpcbEIDNewEntry,
  LPENTRYID FAR * lppEIDNewEntry
);

Parameters

ulUIParam
[in] Handle of the parent window for the dialog box.
ulFlags
Reserved; must be zero.
cbEIDContainer
[in] Count of bytes in the entry identifier pointed to by the lpEIDContainer parameter.
lpEIDContainer
[in] Pointer to the entry identifier of the container to receive the new entry. If cbEIDContainer is zero and lpEIDContainer is NULL, NewEntry creates a one-off entry identifier that is the same type as is generated by a call to IMAPISupport::CreateOneOff.
cbEIDNewEntryTpl
[in] Count of bytes in the entry identifier pointed to by the lpEIDNewEntryTpl parameter.
lpEIDNewEntryTpl
[in] Pointer to the entry identifier of the template to be used to create the new entry. If cbEIDNewEntryTpl is zero and lpEIDNewEntryTpl is NULL, NewEntry displays a dialog box enabling the user to select from a list of templates for adding new entries.
lpcbEIDNewEntry
[out] Pointer to the count of bytes in the entry identifier pointed to by the lppEIDNewEntry parameter.
lppEIDNewEntry
[out] Pointer to a pointer to the entry identifier of the newly created entry.

Return Values

S_OK
The new entry was successfully created.

Remarks

The IMAPISupport::NewEntry method is implemented for address book provider support objects. Address book providers call NewEntry to create a new address book entry to be added directly into a container or to be used to address an outgoing message.

Notes to Callers

If you want the new entry to be added to a specific container, set lpEIDContainer to the container's entry identifier and cbEIDContainer to the count of bytes in the entry identifier.

If you want the new entry to be added to the recipient list of an outgoing message, set lpEIDContainer to NULL and cbEIDContainer to zero.

If you want to allow the user of a client application to select the type of entry to be created, pass zero in cbEIDNewEntryTpl and NULL in lpEIDNewEntryTpl. NewEntry displays the MAPI one-off table — a listing of templates supported by MAPI and by each of the address book providers in the session. Each template can create a recipient entry for one or more address types.

If you want to retain the entry identifier of the new entry, pass valid pointers in the lpcbEIDNewEntry and lppEIDNewEntry parameters. You are responsible for freeing this entry identifier when you have finished with it by calling the MAPIFreeBuffer function.

To use a particular template for adding a new entry to a modifiable container
  1. Call IMAPISupport::OpenEntry to open the destination container, setting the lpEntryID parameter to the entry identifier of the container.
  2. Call the destination container's IMAPIProp::OpenProperty method and set ulPropTag to PR_CREATE_TEMPLATES and lpiid to IID_IMAPITable. The container will return a one-off table listing all of the templates that it supports for creating new entries.
  3. Retrieve the row that represents the template for the particular type of entry you want to create. The PR_ADDRTYPE column indicates the address type that is supported by the template.
  4. Call IMAPISupport::NewEntry and set lpEIDNewEntryTpl to the entry identifier of the selected template. This will be the PR_ENTRYID column from the template's row in the one-off table. Pass zero in cbEIDContainer and NULL in lpEIDContainer. Pass a valid pointer in the lppEIDNewEntry parameter if you want to retain the new entry's entry identifier.

See Also

IMAPIProp::OpenProperty, IMAPISupport::OpenEntry, PR_CREATE_TEMPLATES


IMAPISupport::NewUID

The IMAPISupport::NewUID method creates a new MAPIUID structure to be used as a unique identifier.

Quick Info

See IMAPISupport : IUnknown.

HRESULT NewUID(
  LPMAPIUID lpMuid
);

Parameters

lpMuid
Pointer to the new MAPIUID structure.

Return Values

S_OK
The new MAPIUID structure was created.

Remarks

The IMAPISupport::NewUID method is implemented for all support objects. Service providers and message services call NewUID whenever they need to generate a long-term unique identifier. A message store provider, for instance, might call NewUID to obtain a MAPIUID to place in the PR_SEARCH_KEY property of a newly created message.

Notes to Callers

Do not confuse the MAPIUID structure that you register at logon time with the MAPIUID structures that are created by NewUID. The MAPIUID structure that you register when you call IMAPISupport::SetProviderUID represents your address book or message store provider to MAPI and is used to distinguish entry identifiers created by different providers. This MAPIUID structure should be hard-coded, using the output of the utility UUIDGEN.EXE, and not obtained through a call to NewUID.

See Also

MAPIUID


IMAPISupport::Notify

The IMAPISupport::Notify method sends a notification of a specified event to an advise source that originally registered for the notification through IMAPISupport::Subscribe.

Quick Info

See IMAPISupport : IUnknown.

HRESULT Notify(
  LPNOTIFKEY lpKey,
  ULONG cNotification,
  LPNOTIFICATION lpNotifications,
  ULONG FAR * lpulFlags
);

Parameters

lpKey
[in] Pointer to the notification key for the advise source object. The lpKey parameter cannot be NULL.
cNotification
[in] Count of notification structures pointed to by the lpNotifications parameter.
lpNotifications
[in] Pointer to an array of NOTIFICATION structures describing pending notifications.
lpulFlags
[in, out] Bitmask of flags that controls the notification process. On input, the following flag can be set:
MAPI_UNICODE
The strings in the notification structures pointed to by lpNotifications are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.

On output, the following flag can be set by MAPI:

NOTIFY_CANCELED
A callback function canceled a synchronous notification.

Return Values

S_OK
The notifications were successfully generated.

Remarks

The IMAPISupport::Notify method is implemented for all service provider support objects. Service providers call Notify to request that MAPI generate a notification for an advise sink that has previously registered for the notification through IMAPISupport::Subscribe.

Notify copies the structures pointed to by the lpNotifications parameter into memory and calls the appropriate advise sink's IMAPIAdviseSink::OnNotify method. When finished with the notification, it releases the memory involved. The caller does not need to allocate memory; MAPI performs all necessary memory allocation.

Notes to Callers

The notification key passed in the lpKey parameter should be identical to the key passed in lpKey to the IMAPISupport::Subscribe method. Many providers use the entry identifier of the advise source as the key, but other data, such as a file path, can be used. MAPI uses this key to find all the registrations for notifications on the identified advise source.

Make sure that you set the lpEntryID member of the notification structure to a long-term entry identifier.

If you set the NOTIFY_SYNC flag on the Subscribe call for any of the pending notifications, Notify calls the IMAPIAdviseSink::OnNotify method callback functions before returning. An advise sink can be created manually or by calling HrAllocAdviseSink. The HrAllocAdviseSink function allows its caller to specify a callback function that Notify calls as part of the notification. The callback function conforms to the NOTIFCALLBACK prototype. Callback functions implemented by clients always return S_OK; callback functions implemented by service providers can return CALLBACK_DISCONTINUE.

If a callback function returns CALLBACK_DISCONTINUE, MAPI stops sending notifications and returns NOTIFY_CANCELED in the Notify method's lpulFlags parameter. You can assume that the process is inactive and stop generating notifications for that process. If Notify returns zero in lpulFlags, the process is still active and you should continue to send notifications as appropriate.

When using synchronous notifications, be careful to avoid deadlock situations.

For more information on the notification process, see Event Notification in MAPI.

See Also

IMAPISupport::Subscribe, IMAPISupport::Unsubscribe, NOTIFCALLBACK, NOTIFICATION, NOTIFKEY, PR_RECORD_KEY


IMAPISupport::OpenAddressBook

The IMAPISupport::OpenAddressBook method provides access to the address book.

Quick Info

See IMAPISupport : IUnknown.

HRESULT OpenAddressBook(
  LPCIID lpInterface,
  ULONG ulFlags,
  LPADRBOOK FAR * lppAdrBook
);

Parameters

lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the address book. Valid values are NULL, indicating the standard address book interface — IAddrBook — and IID_IAddrBook.
ulFlags
Reserved; must be zero.
lppAdrBook
[out] Pointer to a pointer to the address book.

Return Values

S_OK
Access to the address book was provided.
MAPI_W_ERRORS_RETURNED
The call succeeded, but one or more address book providers could not be loaded. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IMAPISupport::OpenAddressBook method is implemented for all service provider support objects. Service providers, typically tightly coupled message store and transport providers, call OpenAddressBook to get access to the address book. The returned IAddrBook pointer can be used for a variety of address book tasks, including opening address book containers, finding messaging users, and displaying address dialog boxes.

Notes to Callers

OpenAddressBook can return MAPI_W_ERRORS_RETURNED if it cannot load one or more of the address book providers in the current profile. This value is a warning and you should treat the call as successful. Even if all of the address book providers failed to load, OpenAddressBook still succeeds, returning MAPI_W_ERRORS_RETURNED and an IAddrBook pointer in the lppAdrBook parameter. Because OpenAddressBook always returns a valid IAddrBook pointer, you must release it when you are finished using it.

If one or more address book providers failed to load, call IMAPISupport::GetLastError to obtain a MAPIERROR structure containing information about the providers that did not load.

See Also

IAddrBook : IMAPIProp, IMAPISession::OpenAddressBook


IMAPISupport::OpenEntry

The IMAPISupport::OpenEntry method opens an object and returns an interface pointer for further access.

Quick Info

See IMAPISupport : IUnknown.

HRESULT OpenEntry(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  LPCIID lpInterface,
  ULONG ulOpenFlags,
  ULONG FAR * lpulObjType,
  LPUNKNOWN FAR * lppUnk
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the object to open.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the object. Passing NULL results in the object's standard interface being returned. For example, if the object to be opened is a message, the standard interface is IMessage; for folders, it is IMAPIFolder. The standard interfaces for address book objects are IDistList for a distribution list and IMailUser for a messaging user.
ulOpenFlags
[in] Bitmask of flags that controls how the object is opened. The following flags can be set:
MAPI_BEST_ACCESS
Requests that the object be opened with the maximum network permissions allowed for the caller. For example, if the caller has read/write access, the object should be opened with read/write access; if the caller has read-only access, the object should be opened with read-only access.
MAPI_DEFERRED_ERRORS
Allows OpenEntry to return successfully, possibly before the object is fully accessible to the caller. If the object is not accessible, making a subsequent object call can result in an error.
MAPI_MODIFY
Requests read/write access. By default, objects are opened with read-only access, and callers should not work on the assumption that read/write access has been granted.
lpulObjType
[out] Pointer to the type of the opened object.
lppUnk
[out] Pointer to a pointer to the opened object.

Return Values

S_OK
The object was successfully opened.
MAPI_E_NO_ACCESS
An attempt was made to modify a read-only object or an attempt was made to access an object for which the user has insufficient permissions.
MAPI_E_NOT_FOUND
There is not an object associated with the entry identifier passed in lpEntryID.
MAPI_E_UNKNOWN_ENTRYID
The entry identifier passed in the lpEntryID parameter is in an unrecognizable format. This value is typically returned if the address book provider that contains the object is not open.

Remarks

The IMAPISupport::OpenEntry method is implemented for all service provider support objects. Service providers call OpenEntry to retrieve a pointer to an interface that can be used to access a particular object.

Notes to Callers

Call IMAPISupport::OpenEntry only when you do not know what kind of object you are opening. If you know you are opening a folder or a message, call IMsgStore::OpenEntry instead. If you know you are opening an address book container, a messaging user, or a distribution list, call IAddrBook::OpenEntry. These more specific methods are faster than IMAPISupport::OpenEntry.

OpenEntry opens all objects with read-only access, unless you set the MAPI_MODIFY or MAPI_BEST_ACCESS flag in the ulFlags parameter and your access is sufficient. Setting one of these flags does not guarantee a particular type of access; the permissions that you are granted depends on the service provider that owns the object, your access level, and the object. To determine the access level of the opened object, retrieve its PR_ACCESS_LEVEL property.

Check the value returned in the lpulObjType parameter to determine that the object type returned is what you expected. If the object type is as expected, cast the pointer from the lppUnk parameter to a pointer of the appropriate type. For example, if you are opening a folder, cast lppUnk to a pointer of type LPMAPIFOLDER.


IMAPISupport::OpenProfileSection

The IMAPISupport::OpenProfileSection method opens a section of the current profile and returns an IProfSect pointer for further access.

Quick Info

See IMAPISupport : IUnknown.

HRESULT OpenProfileSection(
  LPMAPIUID lpUid,
  ULONG ulFlags,
  LPPROFSECT FAR * lppProfileObj
);

Parameters

lpUid
[in] Pointer to the MAPIUID structure that identifies the profile section to be opened. Passing NULL for the lpUid parameter opens the caller's profile section.
ulFlags
[in] Bitmask of flags that controls how the profile section is opened. The following flags can be set:
MAPI_DEFERRED_ERRORS
Allows OpenProfileSection to return successfully, possibly before the profile section is fully accessible to the caller. If the profile section is not accessible, making a subsequent object call can result in an error.
MAPI_MODIFY
Requests read/write access. By default, objects are opened with read-only access, and callers should not work on the assumption that read/write access has been granted.
lppProfileObj
[out] Pointer to a pointer to the opened profile section.

Return Values

S_OK
The profile section was successfully opened.
MAPI_E_NO_ACCESS
An attempt was made to modify a read-only profile section or to access an object for which the caller has insufficient permissions.
MAPI_E_NOT_FOUND
There is not a profile section associated with the entry identifier passed in lpEntryID.
MAPI_E_UNKNOWN_FLAGS
Reserved or unsupported flags were used, and therefore the operation did not complete.

Remarks

The IMAPISupport::OpenProfileSection method is implemented for all support objects. Service providers and message services call OpenProfileSection to open a profile section and retrieve a pointer to its IProfSect interface implementation.

Notes to Callers

OpenProfileSection opens profile sections with read-only access, unless you set the MAPI_MODIFY flag in the ulFlags parameter and your access is sufficient. Setting this flag does not guarantee read/write access; the permissions that you are granted depends on your access level and the object.

If OpenProfileSection attempts to open a nonexistent profile section with read-only access, it returns MAPI_E_NOT_FOUND. If OpenProfileSection attempts to open a nonexistent profile section with read/write access, it creates the profile section and returns the IProfSect pointer.

See Also

IMAPIProp : IUnknown, IProfSect : IMAPIProp, MAPIUID


IMAPISupport::OpenTemplateID

The IMAPISupport::OpenTemplateID method opens a recipient entry in a foreign address book provider.

Quick Info

See IMAPISupport : IUnknown.

HRESULT OpenTemplateID(
  ULONG cbTemplateID,
  LPENTRYID lpTemplateID,
  ULONG ulTemplateFlags,
  LPMAPIPROP lpMAPIPropData,
  LPCIID lpInterface,
  LPMAPIPROP FAR * lppMAPIPropNew,
  LPMAPIPROP lpMAPIPropSibling
);

Parameters

cbTemplateID
[in] Count of bytes in the template identifier pointed to by lpTemplateID.
lpTemplateID
[in] Pointer to the template identifier — PR_TEMPLATEID property — of the recipient entry to be opened.
ulTemplateFlags
[in] Bitmask of flags used to describe how to open the entry. The following flag can be set:
FILL_ENTRY
A new entry is being created. When the foreign provider receives the subsequent IABLogon::OpenTemplateID call from MAPI, it can control how the entry is created by modifying properties pointed to by the lpMAPIPropData parameter or by returning a specific interface implementation in lppMAPIPropNew to control how properties for the new entry are set.
lpMAPIPropData
[in] Pointer to the interface implementation that the caller uses to access the entry. This is the implementation that the foreign provider can wrap with its own implementation and return in the lppMAPIPropNew parameter. The lpMAPIPropData parameter must point to a read/write interface implementation that derives from IMAPIProp and supports the interface being requested in the lpInterface parameter.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the entry. The lppMAPIPropNew parameter points to an interface of the type specified by lpInterface. Passing NULL results in the return of the standard interface for a messaging user, IID_IMailUser.
lppMAPIPropNew
[out] Pointer to the interface implementation supplied by the foreign provider for accessing the entry.
lpMAPIPropSibling
Reserved; must be NULL.

Return Values

S_OK
The binding process was successful.
MAPI_E_UNKNOWN_ENTRYID
The foreign address book provider doesn't exist.

Remarks

The IMAPISupport::OpenTemplateID method is implemented only for address book provider support objects. OpenTemplateID is called only by address book providers that can act as hosts for entries belonging to other address book providers, also known as foreign providers. Host providers call OpenTemplateID to open a foreign entry, which occurs when data in the host provider is bound to code in the foreign provider.

Notes to Callers

Call OpenTemplateID only if you support the storage of entries with template identifiers from foreign address book providers. Such support places additional requirements on your IABContainer::CreateEntry and IABLogon::OpenEntry implementations. See the descriptions of these methods and Acting as a Host Address Book Provider for more information.

If the OpenTemplateID call returns as the bound interface the same property object implementation as you passed in, you can release your reference to your property object. This is because the foreign provider has called the object's AddRef method to keep its own reference. If the foreign provider does not need to keep a reference to the property object, then OpenTemplateID will return the unbound property object.

If OpenTemplateID fails with MAPI_E_UNKNOWN_ENTRYID, try to continue by treating the entry as read-only.

See Also

IABLogon::OpenTemplateID, IPropData : IMAPIProp, PR_TEMPLATEID


IMAPISupport::PrepareSubmit

The IMAPISupport::PrepareSubmit method prepares a message for submission to the MAPI spooler.

Quick Info

See IMAPISupport : IUnknown.

HRESULT PrepareSubmit(
  LPMESSAGE lpMessage,
  ULONG FAR * lpulFlags
);

Parameters

lpMessage
[in] Pointer to the message to prepare.
lpulFlags
[in, out] On input, the lpulFlags parameter is reserved and must be zero. On output, lpulFlags must be NULL.

Return Values

S_OK
The message was successfully prepared.

Remarks

The IMAPISupport::PrepareSubmit method is implemented for message store provider support objects. Message store providers call PrepareSubmit in their implementation of IMessage::SubmitMessage to prepare a message for submission to the MAPI spooler.

PrepareSubmit is used to handle messages that have the MSGFLAG_RESEND flag set in their PR_MESSAGE_FLAGS property. MSGFLAG_RESEND is set for messages that include a request to be resent when an initial transmission fails. PrepareSubmit determines which of the recipients in the recipient list successfully received the message and which did not.

To access the recipient list, PrepareSubmit calls the message's IMessage::GetRecipientTable method. To retrieve the recipient data, PrepareSubmit calls the recipient table's IMAPITable::QueryRows. For each row in the table, PrepareSubmit checks PR_RECIPIENT_TYPE, and:

  • If the MAPI_SUBMITTED flag is set, PrepareSubmit clears the flag and sets the PR_RESPONSIBILITY property to FALSE.
  • If the MAPI_SUBMITTED flag is not set, PrepareSubmit changes the PR_RECIPIENT_TYPE to MAPI_P1 and sets the PR_RESPONSIBILITY property to TRUE.

Notes to Callers

Before you call PrepareSubmit, make sure you have called IMAPISupport::SpoolerNotify and set the NOTIFY_READYTOSEND flag in the ulFlags parameter. The SpoolerNotify call must be made once per session before the call to PrepareSubmit. SpoolerNotify synchronizes the MAPI spooler and ensures that all needed transport providers are logged on and their address types registered.

See Also

IMAPIFolder::GetMessageStatus, IMessage::SubmitMessage


IMAPISupport::ReadReceipt

The IMAPISupport::ReadReceipt method generates a read or nonread report for a message.

Quick Info

See IMAPISupport : IUnknown.

HRESULT ReadReceipt(
  ULONG ulFlags,
  LPMESSAGE lpReadMessage,
  LPMESSAGE FAR * lppEmptyMessage
);

Parameters

ulFlags
[in] Bitmask of flags that controls how the read or nonread report is generated. The following flag can be set:
MAPI_NON_READ
A nonread report is generated. If MAPI_NON_READ is not set, a read report is generated.
lpReadMessage
[in] Pointer to the message about which the report should be generated.
lppEmptyMessage
[in, out] On input, lppEmptyMessage points to a pointer to an empty message. On output, lppEmptyMessage points to a pointer to the report message.

Return Values

S_OK
The report was successfully generated.

Remarks

The IMAPISupport::ReadReceipt method is implemented for message store provider support objects only. Message store providers call ReadReceipt to instruct MAPI to generate a read or nonread report for the message pointed to by the lpReadMessage parameter.

Notes to Callers

Call ReadReceipt when the PR_READ_RECEIPT_REQUESTED property is set and one of the following conditions is true:

  • The message has been read.
  • The message has been moved.
  • The message has been copied.
  • The message's IMessage::SetReadFlag method has been called.

Do not call ReadReceipt when a message is deleted.

A read or nonread report should only be sent once for a message. Keep track of a message's read status and do not send multiple reports for a single message.

If lppEmptyMessage points to a valid report message when MAPI returns from ReadReceipt, call its IMessage::SubmitMessage method to send it and then release it by calling its IUnknown::Release method.

If ReadReceipt fails, the message should be released without being submitted. If you store the message's read status, you can attempt to generate the read or nonread report at a later time.

You can either hide or display read and nonread reports generated by stores in your folders. Storing read and nonread reports in hidden folders allows you to implement tighter security.

See Also

IMAPIFolder::DeleteMessages, IMessage::SubmitMessage, PR_READ_RECEIPT_REQUESTED


IMAPISupport::RegisterPreprocessor

The IMAPISupport::RegisterPreprocessor method registers a transport provider's preprocessor function — a function that conforms to the PreprocessMessage prototype.

Quick Info

See IMAPISupport : IUnknown.

HRESULT RegisterPreprocessor(
  LPMAPIUID lpMuid,
  LPTSTR lpszAdrType,
  LPTSTR lpszDLLName,
  LPSTR lpszPreprocess,
  LPSTR lpszRemovePreprocessInfo,
  ULONG ulFlags
);

Parameters

lpMuid
[in] Pointer to the MAPIUID structure containing the identifier that the preprocessor function handles. The lpMuid parameter can be NULL.
lpszAdrType
[in] Pointer to the address type for the messages the function operates on, such as FAX, SMTP, or X500. The lpszAdrType parameter can be NULL.
lpszDLLName
[in] Pointer to the name of the dynamic-link library (DLL) containing the entry point for the preprocessor function.
lpszPreprocess
[in] Pointer to the name of the preprocessor function. The lpszPreprocess parameter can be NULL.
lpszRemovePreprocessInfo
[in] Pointer to the name of the function that removes preprocessor information — a function that conforms to the RemovePreprocessInfo prototype. The lpszRemovePreprocessInfo parameter can be NULL.
ulFlags
Reserved; must be zero.

Return Values

S_OK
The preprocessor function was successfully registered.

Remarks

The IMAPISupport::RegisterPreprocessor method is implemented for transport provider support objects only. Transport providers call RegisterPreprocessor to register a preprocessor function — a function that conforms to the PreprocessMessage prototype. A preprocessor function must be registered before it can be called by the MAPI spooler.

The lpszPreprocess, lpszRemovePreprocessInfo and lpszDLLName parameters should all point to strings that can be used in conjunction with calls to the Win32 GetProcAddress function, allowing the preprocessor's DLL entry point to be called correctly.

Notes to Callers

Calls to preprocessors are specific to transport provider order. This means that if another transport provider ahead of your provider is able to handle a message, your preprocessor function will not get called for that message. Your preprocessor function will only be called for messages that you will handle.

Preprocessor functions can be written to handle either a specific identifier stored in a MAPIUID structure or a type of address. If you specify both a MAPIUID structure in the lpMuid parameter and an address type in lpszAdrType, your function will be called for message recipients that match either the MAPIUID or the address type. If lpMuid is NULL and lpszAdrType is non-null, your function will be called only for recipients with an address that matches the type pointed to by lpszAdrType. If lpMuid is non-null and lpszAdrType is NULL, your function will be called for recipients that match MAPIUID, regardless of their address type. If both are NULL, your function is called for all recipients of the message.

See Also

MAPIUID, PreprocessMessage, RemovePreprocessInfo


IMAPISupport::SetProviderUID

The IMAPISupport::SetProviderUID method registers a MAPIUID structure that uniquely represents the service provider.

Quick Info

See IMAPISupport : IUnknown.

HRESULT SetProviderUID(
  LPMAPIUID lpProviderID,
  ULONG ulFlags
);

Parameters

lpProviderID
[in] Pointer to the MAPIUID structure identifying the address book or message store provider.
ulFlags
Reserved; must be zero.

Return Values

S_OK
The MAPIUID structure was successfully registered.

Remarks

The IMAPISupport::SetProviderUID method is implemented for address book and message store provider support objects. These providers call SetProviderUID to register a unique identifier described in the MAPIUID structure pointed to by lpProviderID. Providers include this identifier in all of the entry identifiers that they create.

MAPI uses the MAPIUID when sending outbound messages to the MAPI spooler and to determine the appropriate provider for handling client requests. For example, when a client calls IMAPISession::OpenEntry, MAPI examines the MAPIUID portion of the entry identifier, maps it to the provider that passed it to SetProviderUID, and calls that provider's OpenEntry.

Notes to Callers

Call SetProviderUID at logon time to register your MAPIUID structure. MAPI allows address book and message store providers to register multiple identifiers. When you make multiple calls to SetProviderUID, it always adds the MAPIUID structure to the provider's set of MAPIUIDs, even if the MAPIUID is a duplicate. SetProviderUID cannot remove a MAPIUID.

See Also

MAPIUID


IMAPISupport::SpoolerNotify

The IMAPISupport::SpoolerNotify method notifies the MAPI spooler of a change in status or a request for service.

Quick Info

See IMAPISupport : IUnknown.

HRESULT SpoolerNotify(
  ULONG ulFlags,
  LPVOID lpvData
);

Parameters

ulFlags
[in] Bitmask of flags that indicates the type of notification. All of the flags except for NOTIFY_NEWMAIL_RECEIVED can be set by transport providers; only NOTIFY_NEWMAIL_RECEIVED and NOTIFY_READTOSEND are valid for message store providers.

The following flags are valid for the ulFlags parameter::

NOTIFY_CONFIG_CHANGE
Registers a request to change the transport provider's configuration.
NOTIFY_CRITICAL_ERROR
An unrecoverable error has occurred to the transport provider. Because both NOTIFY_SENTDEFERRED and NOTIFY_CRITICAL_ERROR use the lpvData parameter for transport provider calls, these flags are mutually exclusive.
NOTIFY_CRITSEC
Requests a critical section for the transport provider. The lpvData parameter is undefined and should be NULL.
NOTIFY_NEWMAIL
The MAPI spooler should download any newly received messages at the next available time. The lpvData parameter is undefined and should be set to NULL.
NOTIFY_NEWMAIL_RECEIVED
A new message has been received in the message store. The lpvData parameter points to a NEWMAIL_NOTIFICATION structure describing the message. This flag is used for message store providers that are tightly coupled with transport providers and is ignored if the store provider logged on with the MAPI_NO_MAIL flag set.
NOTIFY_NONCRIT
Releases a critical section that was obtained with a previous call to SpoolerNotify with ulFlags set to NOTIFY_CRITSEC. The lpvData parameter is undefined and should be set to NULL.
NOTIFY_READYTOSEND
The transport or message store provider is ready to send messages. The lpvData parameter is undefined and should be set to NULL.
NOTIFY_SENTDEFERRED
A previously deferred message should now be sent and the transport provider should be notified when it is ready to be delivered with a call to IXPLogon::SubmitMessage. The entry identifier of the deferred message is contained in an SBinary structure pointed to by lpvData. Because both NOTIFY_SENTDEFERRED and NOTIFY_CRITICAL_ERROR use the lpvData parameter, these flags are mutually exclusive.
lpvData
[in] Pointer to associated data applicable to a notification. The lpvData parameter points to valid data only when the following flags are set; lpvData is NULL when ulFlags is set to the other notification types:
Setting for ulFlags | Value for lpvData
NOTIFY_CRITICAL_ERROR | Information about the error.
NOTIFY_NEWMAIL_RECEIVED | NEWMAIL_NOTIFICATION structure with information about the newly delivered message.
NOTIFY_SENTDEFERRED | SBinary structure with entry identifier of deferred message.

Return Values

S_OK
The notification was successful.

Remarks

The IMAPISupport::SpoolerNotify method is implemented for message store and transport provider support objects. These providers call SpoolerNotify to notify the MAPI spooler of a change in status or a request for service. SpoolerNotify is called primarily by transport providers and may be called at any time during the session.

Notes to Transport Providers

If you have changed your configuration, call SpoolerNotify and set ulFlags to NOTIFY_CONFIG_CHANGED. SpoolerNotify responds by calling your IXPLogon::AddressTypes method to query for a change in supported address types and the IMAPISession::MessageOptions method to ask MAPI to display your configuration properties to the user.

If you need a critical section to ensure uninterrupted processing, call SpoolerNotify with ulFlags set to NOTIFY_CRITSEC. Setting this flag informs the MAPI spooler that it should not call your IXPLogon::Idle and IXPLogon::Poll methods. While you have a critical section open, return MAPI_E_BUSY whenever your IMAPIStatus::ValidateState method is called. When you have finished with the critical section, make another call to SpoolerNotify with ulFlags set to NOTIFY_NONCRIT.

For example, if you are a remote transport provider in the process of uploading messages, you might need to allow a user to enter a telephone number for establishing the remote connection. Before looping through your dialog box procedure, declare a critical section. When the user closes the dialog box, terminating the dialog box procedure, release the critical section.

When you set ulFlags to NOTIFY_CRITICAL_ERROR, the MAPI spooler makes no further calls to your provider except to release it. If you call SpoolerNotify with this flag set from IXPLogon::StartMessage or IXPLogon::SubmitMessage, return with an appropriate error value from the StartMessage or SubmitMessage call immediately after the SpoolerNotify call.

If you have recovered from a condition that previously caused you to fail, call SpoolerNotify with ulFlags set to NOTIFY_READYTOSEND. This flag indicates that you are again ready to handle messages.

Notes to Message Store Providers

Call SpoolerNotify, passing the NOTIFY_READYTOSEND flag in ulFlags, before you make your first call to IMAPISupport::PrepareSubmit in IMessage::SubmitMessage. This call to SpoolerNotify only needs to be made once per session.

If you are tightly coupled with a transport provider and you call SpoolerNotify with ulFlags set to NOTIFY_NEWMAIL_RECEIVED, the MAPI spooler opens the new message and begins processing the new message hook function. When processing is complete, the MAPI spooler calls your IMsgStore::NotifyNewMail method to inform you of your own new message.

For more information about calling SpoolerNotify, see any of the following topics:

Implementing the FlushQueues Method

Interacting with the MAPI Spooler

Message Reception Model

See Also

IMsgStore::NotifyNewMail, IXPLogon::StartMessage, IXPLogon::SubmitMessage


IMAPISupport::SpoolerYield

The IMAPISupport::SpoolerYield method gives control of the CPU to the the MAPI spooler so that it can perform any tasks it deems necessary.

Quick Info

See IMAPISupport : IUnknown.

HRESULT SpoolerYield(
  ULONG ulFlags
);

Parameters

ulFlags
Reserved; must be zero.

Return Values

S_OK
The transport provider successfully released the CPU.
MAPI_W_CANCEL_MESSAGE
Instructs the transport provider to stop the delivery of the message to any recipients that have not yet received it.

Remarks

The IMAPISupport::SpoolerYield method is implemented for transport provider support objects. Transport providers call SpoolerYield to allow the MAPI spooler to accomplish any necessary processing.

Notes to Callers

Call SpoolerYield when you are performing lengthy operations that can be paused. This allows foreground applications to run during a long operation, such as delivery to a large recipient list across a busy network.

If SpoolerYield returns with MAPI_W_CANCEL_MESSAGE, the MAPI spooler has determined that the message should no longer be sent. Return MAPI_E_USER_CANCEL to your calling process and exit if possible.

For more information about yielding to the MAPI spooler, see Interacting with the MAPI Spooler.


IMAPISupport::StatusRecips

The IMAPISupport::StatusRecips method generates delivery and nondelivery reports.

Quick Info

See IMAPISupport : IUnknown.

HRESULT StatusRecips(
  LPMESSAGE lpMessage,
  LPADRLIST lpRecipList
);

Parameters

lpMessage
[in] Pointer to the message for which the report should be generated.
lpRecipList
[in] Pointer to an ADRLIST structure describing the recipients of the message pointed to by lpMessage.

Return Values

S_OK
The report was successfully generated.
MAPI_W_ERRORS_RETURNED
The call succeeded overall, but there are no recipient options for this type of recipient. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IMAPISupport::StatusRecips method is implemented for transport provider support objects. Transport providers call StatusRecips to request that MAPI send a delivery or nondelivery report to a set of one or more of the recipients of a message.

Notes to Callers

You can call StatusRecips multiple times during the processing of a message. However, if you call StatusRecips for an open message, do your best to collect all delivery and nondelivery information for the message recipients and call StatusRecips for that recipient list. A single point of collection is important because multiple StatusRecips calls for one recipient can result in multiple identical reports being sent.

Store properties relating to message delivery or nondelivery in the ADRLIST structure indicated by the lpRecipList parameter. For a complete list of required and optional properties for delivery reports and nondelivery reports, see Required Report Message Properties and Optional Report Message Properties.

Allocate memory for the ADRLIST structure in lpRecipList using the MAPIAllocateBuffer and MAPIAllocateMore functions. MAPI releases the memory by calling the MAPIFreeBuffer function only if IMAPISupport::StatusRecips succeeds.

For an overview of delivery and nondelivery reports, see Report Messages.

See Also

ADRLIST, IMAPISupport::Address, IMAPISupport::SpoolerNotify, IXPLogon::EndMessage, MAPIAllocateBuffer, MAPIAllocateMore, MAPIFreeBuffer


IMAPISupport::StoreLogoffTransports

The IMAPISupport::StoreLogoffTransports method requests the orderly release of a message store.

Quick Info

See IMAPISupport : IUnknown.

HRESULT StoreLogoffTransports(
  ULONG FAR * lpulFlags
);

Parameters

lpulFlags
[in, out] Bitmask of flags that controls how message store logoff occurs. On input, all flags for this parameter are mutually exclusive; only one of the following flags can be set per call:
LOGOFF_ABORT
Any transport provider activity for this store should be stopped before logoff. Control is returned to the client after the activity is stopped and the MAPI spooler has logged off the store. If any transport activity is taking place, the logoff does not occur and no change in MAPI spooler or transport provider behavior occurs. If there is currently no activity, the MAPI spooler releases the store.
LOGOFF_NO_WAIT
The MAPI spooler should release the store and return control to the client immediately after all outbound mail that is ready to be sent is sent. If the message store has the default Inbox, any in-process message is received and then further reception is disabled.
LOGOFF_ORDERLY
The MAPI spooler should release the store and return control to the client immediately after any pending messages have finished processing. No new messages should be processed.
LOGOFF_PURGE
Works the same as the LOGOFF_NO_WAIT flag. The LOGOFF_PURGE flag returns control to the caller after completion.
LOGOFF_QUIET
The logoff should not occur if any transport provider activity is taking place. The type of activity taking place is returned as a flag on output.

On output, the MAPI spooler can return one or more of the following flags:

LOGOFF_COMPLETE
The logoff can complete. All resources associated with the store have been released, and the object has been invalidated. The MAPI spooler has performed or will perform all requests. Only the message store's IUnknown::Release method should be called at this point.
LOGOFF_INBOUND
A message is currently coming into the store from one or more transport providers.
LOGOFF_OUTBOUND
A message is currently being sent from the store by one or more transport providers.
LOGOFF_OUTBOUND_QUEUE
There are currently messages in the outbound queue for the store.

Return Values

S_OK
The logoff procedure was successful.

Remarks

The IMAPISupport::StoreLogoffTransports method is implemented for message store provider support objects. Message store providers call StoreLogoffTransports to give client applications some control over how MAPI handles transport provider activity as a message store is closing.

If another process has the store to be logged off open for the same profile, MAPI ignores a call to StoreLogoffTransports and returns the flag LOGOFF_COMPLETE in lpulFlags.

The behavior of the store provider following the return from StoreLogoffTransports should be based on the value of lpulFlags, which indicates system status and conveys client instructions on logoff behavior.

Notes to Callers

StoreLogoffTransports is typically called from a store provider's IMsgStore::StoreLogoff method. However, it can also be called from the IUnknown::Release method of the message store. Implement the Release method of your message store so that you can check whether or not a call to StoreLogoffTransports has occurred. If not, call it with the LOGOFF_ABORT flag set.

The lpulFlags parameter is set to a flag that indicates how the client requires the message store to be shut down. Determine the appropriate setting for ulFlags based on the setting of the corresponding parameter in the call to the IMsgStore::StoreLogoff method. That is, if a client called your StoreLogoff method with ulFlags set to LOGOFF_ORDERLY, you should call StoreLogoffTransports with ulFlags set to LOGOFF_ORDERLY.

For more information about the message store logoff process, see Shutting Down a Message Store Provider.

See Also

IMsgStore::StoreLogoff, IXPLogon::FlushQueues


IMAPISupport::Subscribe

The IMAPISupport::Subscribe method registers an advise sink to receive notifications through MAPI.

Quick Info

See IMAPISupport : IUnknown.

HRESULT Subscribe(
  LPNOTIFKEY lpKey,
  ULONG ulEventMask,
  ULONG ulFlags,
  LPMAPIADVISESINK lpAdviseSink,
  ULONG FAR * lpulConnection
);

Parameters

lpKey
[in] Pointer to a notification key that represents the advise source object. The lpKey parameter cannot be NULL.
ulEventMask
[in] A mask of values indicating the types of notification events that the caller is interested in and should be included in the registration. The following values are valid:
fnevCriticalError
Registers for notifications about severe errors, such as insufficient memory.
fnevExtended
Registers for notifications about events specific to the particular address book or message store provider.
fnevNewMail
Registers for notifications about the arrival of new messages.
fnevObjectCreated
Registers for notifications about the creation of a new object.
fnevObjectCopied
Registers for notifications about an object being copied.
fnevObjectDeleted
Registers for notifications about an object being deleted.
fnevObjectModified
Registers for notifications about an object being modified.
fnevObjectMoved
Registers for notifications about an object being moved.
fnevSearchComplete
Registers for notifications about the completion of a search operation.
ulFlags
[in] Bitmask of flags that controls how notification occurs. The following flag can be set:
NOTIFY_SYNC
When the caller calls IMAPISupport::Notify to generate notifications for this advise sink, Notify should make all necessary calls to advise sinks before returning. If this flag is not set, notification is asynchronous and callbacks are queued to the processes that have subscribed and started when those processes gain control of the CPU.
lpAdviseSink
[in] Pointer to an advise sink object.
lpulConnection
[out] Pointer to a non-zero connection number representing the registration.

Return Values

S_OK
The notification registration was successful.

Remarks

The IMAPISupport::Subscribe method is implemented for all service provider support objects. Service providers call Subscribe from one of their Advise methods to allow MAPI to manage the notifications.

Notes to Callers

To use the MAPI support methods for notification, create a key for the advise source — the object about which notifications should be generated. The value of the key must be unique and should be easily regenerated each time the object changes.

MAPI uses the notification key to search for any callback functions registered through the HrAllocAdviseSink function for the corresponding advise source. Pass this key to IMAPISupport::Notify whenever you need to generate a notification for the corresponding advise source.

The NOTIFY_SYNC flag affects the operation of subsequent calls to Notify. When you set NOTIFY_SYNC, Notify does not return until it has finished sending all of the necessary notifications. When you do not set NOTIFY_SYNC, Notify operates asynchronously, possibly returning before all of the notifications have been sent.

See Also

HrAllocAdviseSink, IMAPIAdviseSink::OnNotify, IMAPISupport::Notify, NOTIFICATION, NOTIFKEY


IMAPISupport::Unsubscribe

The IMAPISupport::Unsubscribe method cancels the responsibility for sending notifications that was previously established with a call to the IMAPISupport::Subscribe method.

Quick Info

See IMAPISupport : IUnknown.

HRESULT Unsubscribe(
  ULONG ulConnection
);

Parameters

ulConnection
[in] The non-zero connection number representing the notification registration previously established through IMAPISupport::Subscribe.

Return Values

S_OK
The notification registration was canceled.
MAPI_E_NOT_FOUND
The connection number passed in the ulConnection parameter does not exist.

Remarks

The IMAPISupport::Unsubscribe method is implemented for all service provider support objects. Service providers call Unsubscribe to cancel a notification registration previously set up by Subscribe. Unsubscribe cancels the registration by releasing the advise sink pointer passed in the Subscribe call.

Generally, the advise sink's IUnknown::Release method is called during the Unsubscribe call, but if another thread is in the process of calling the IMAPIAdviseSink::OnNotify method for the advise sink object, the Release call is delayed until the OnNotify method returns.

See Also

IMAPIAdviseSink::OnNotify, IMAPISupport::Subscribe


IMAPISupport::WrapStoreEntryID

The IMAPISupport::WrapStoreEntryID method converts a message store's internal entry identifier to an entry identifier in the MAPI standard format.

Quick Info

See IMAPISupport : IUnknown.

HRESULT WrapStoreEntryID(
  ULONG cbOrigEntry,
  LPENTRYID lpOrigEntry,
  ULONG FAR * lpcbWrappedEntry,
  LPENTRYID FAR * lppWrappedEntry
);

Parameters

cbOrigEntry
[in] Count of bytes in the entry identifier pointed to by the lpOrigEntry parameter.
lpOrigEntry
[in] Pointer to the private entry identifier for the message store.
lpcbWrappedEntry
[out] Pointer to the count of bytes in the entry identifier pointed to by the lppWrappedEntry parameter.
lppWrappedEntry
[out] Pointer to a pointer to the wrapped entry identifier.

Return Values

S_OK
The entry identifier was successfully wrapped.

Remarks

The IMAPISupport::WrapStoreEntryID method is implemented for all service provider support objects. Service providers use WrapStoreEntryID to have MAPI generate an entry identifier for a message store that wraps the store's internal entry identifier.

Notes to Callers

When a client calls your message store's IMAPIProp::GetProps method to retrieve its PR_STORE_ENTRYID property and your message store uses an entry identifier in a private format, call WrapStoreEntryID and return the entry identifier pointed to by lppWrappedEntry.

Calls to the IMSProvider::Logon and IMSLogon::CompareEntryIDs methods always obtain the store's private entry identifier; the wrapped version is used only between client applications and MAPI.

Free the memory for the entry identifier pointed to by the lppWrappedEntry parameter using the MAPIFreeBuffer function when you have finished using it.

See Also

IMAPIProp::GetProps, IMAPISupport::CompareEntryIDs, IMSLogon::CompareEntryIDs, IMSProvider::Logon, MAPIFreeBuffer


IMAPITable : IUnknown

The IMAPITable interface is used to provide a read-only view of a table. IMAPITable is used by clients and service providers to manipulate the way a table appears.

Quick Info

Header file: | MAPIDEFS.H
Exposed by: | Table objects
Implemented by: | Service providers and MAPI
Called by: | Client applications, service providers
Interface identifier: | IID_IMAPITable
Pointer type: | LPMAPITABLE

Vtable Order

GetLastError | Returns a MAPIERROR structure containing information about the previous error on the table.
Advise | Registers to receive notification of specified events affecting the table.
Unadvise | Cancels the sending of notifications previously set up with a call to the IMAPITable::Advise method.
GetStatus | Returns the table's status and type.
SetColumns | Defines the particular properties and order of properties to appear as columns in the table.
QueryColumns | Returns a list of columns for the table.
GetRowCount | Returns the total number of rows in the table.
SeekRow | Moves the cursor to a specific position in the table.
SeekRowApprox | Moves the cursor to an approximate fractional position in the table.
QueryPosition | Retrieves the current table row position of the cursor, based on a fractional value.
FindRow | Finds the next row in a table that matches specific search criteria.
Restrict | Applies a filter to a table, reducing the row set to only those rows matching the specified criteria.
CreateBookmark | Marks the table's current position.
FreeBookmark | Releases the memory associated with a bookmark.
SortTable | Orders the rows of the table based on sort criteria.
QuerySortOrder | Retrieves the current sort order for a table.
QueryRows | Returns one or more rows from a table, beginning at the current cursor position.
Abort | Stops any asynchronous operations currently in progress for the table.
ExpandRow | Expands a collapsed table category, adding the leaf rows belonging to the category to the table view.
CollapseRow | Collapses an expanded table category, removing the leaf rows belonging to the category from the table view.
WaitForCompletion | Suspends processing until one or more asynchronous operations in progress on the table have completed.
GetCollapseState | Returns the data necessary to rebuild the current collapsed or expanded state of a categorized table.
SetCollapseState | Rebuilds the current expanded or collapsed state of a categorized table using data that was saved by a prior call to the IMAPITable::GetCollapseState method.


IMAPITable::Abort

The IMAPITable::Abort method stops any asynchronous operations currently in progress for the table.

Quick Info

See IMAPITable : IUnknown.

HRESULT Abort();

Parameters

None

Return Values

S_OK
One or more asynchronous operations have been stopped.
MAPI_E_UNABLE_TO_ABORT
An asynchronous operation is in progress and cannot be stopped or it has already completed.

Remarks

The IMAPITable::Abort method stops any asynchronous operation that is currently in progress.

Notes to Callers

To find out if an asynchronous operation is in progress, call the IMAPITable::GetStatus method.

If Abort halts the processing of a call to the IMAPITable::Restrict method, the state of the table will be as it was at the time the Abort call is processed.

If Abort halts the processing of a call to the IMAPITable::SortTable method, the table's sort order is unaffected and remains as it was before the SortTable call.

See Also

IMAPITable::GetStatus, IMAPITable::Restrict, IMAPITable::SortTable


IMAPITable::Advise

The IMAPITable::Advise method registers to receive notification of specified events affecting the table.

Quick Info

See IMAPITable : IUnknown.

HRESULT Advise(
  ULONG ulEventMask,
  LPMAPIADVISESINK lpAdviseSink,
  ULONG FAR * lpulConnection
);

Parameters

ulEventMask
[in] Value indicating the type of event that will generate the notification. Only the following value is valid:
fnevTableModified
lpAdviseSink
[in] Pointer to an advise sink object to receive the subsequent notifications. This advise sink object must have been already allocated.
lpulConnection
[out] Pointer to a nonzero value that represents the successful notification registration.

Return Values

S_OK
The notification registration successfully completed.
MAPI_E_NO_SUPPORT
The table implementation either does not support changes to its rows and columns or does not support notification.

Remarks

Use the IMAPITable::Advise method to register a table object implemented in the provider for notification callbacks. Whenever a change occurs to the table object, the provider checks to see what event mask bit was set in the ulEventMask parameter and thus what type of change occurred. If a bit is set, then the provider calls the IMAPIAdviseSink::OnNotify method for the advise sink object indicated by the lpAdviseSink parameter to report the event. Data passed in the notification structure to the OnNotify routine describes the event.

The call to OnNotify can occur during the call that changes the object, or at any following time. On systems that support multiple threads of execution, the call to OnNotify can occur on any thread. For a way to turn a call to OnNotify that might happen at an inopportune time into one that is safer to handle, a provider should use the HrThisThreadAdviseSink function.

To provide notifications, the provider implementing Advise needs to keep a copy of the pointer to the lpAdviseSink advise sink object; to do so, it calls the IUnknown::AddRef method for the advise sink to maintain its object pointer until notification registration is canceled with a call to the IMAPITable::Unadvise method. The Advise implementation should assign a connection number to the notification registration and call AddRef on this connection number before returning it in the lpulConnection parameter. Service providers can release the advise sink object before the registration is canceled, but they must not release the connection number until Unadvise has been called.

After a call to Advise has succeeded and before Unadvise has been called, clients must be prepared for the advise sink object to be released. A client should therefore release its advise sink object after Advise returns unless it has a specific long-term use for it.

Because of the asynchronous behavior of notification, implementations that change table column settings can receive notifications with information organized in a previous column order. For instance, a table row might be returned for a message that has just been deleted from the container. Such a notification is sent when the column setting change has been made and information about it sent but the notification table view has not been updated with that information yet.

For more information on the notification process, see Event Notification in MAPI. For specific information about table notification, see About Table Notifications. For information about using the IMAPISupport methods to support notification, see Supporting Event Notification.

See Also

HrThisThreadAdviseSink, IMAPIAdviseSink::OnNotify, IMAPITable::Unadvise, TABLE_NOTIFICATION


IMAPITable::CollapseRow

The IMAPITable::CollapseRow method collapses an expanded table category, removing the leaf rows belonging to the category from the table view.

Quick Info

See IMAPITable : IUnknown.

HRESULT CollapseRow(
  ULONG cbInstanceKey,
  LPBYTE pbInstanceKey,
  ULONG ulFlags,
  ULONG FAR * lpulRowCount
);

Parameters

cbInstanceKey
[in] Count of bytes in the PR_INSTANCE_KEY property pointed to by the pbInstanceKey parameter.
pbInstanceKey
[in] Pointer to the PR_INSTANCE_KEY property that identifies the heading row for the category.
ulFlags
Reserved; must be zero.
lpulRowCount
[out] Pointer to the total number of rows that are being removed from the table view.

Return Values

S_OK
The collapse operation has succeeded.
MAPI_E_NOT_FOUND
The row identified by the pbInstanceKey parameter does not exist.
MAPI_E_INVALID_ENTRYID
The row identified by the pbInstanceKey parameter does not exist. This error is an alternative to MAPI_E_NOT_FOUND; service providers can return either one.

Remarks

The IMAPITable::CollapseRow method collapses a table category and removes it from the table view. The rows are collapsed starting at the row identified by the PR_INSTANCE_KEY property pointed to by the pbInstanceKey parameter. The number of rows that are removed from the view is returned in the contents of the lpulRowCount parameter.

Notifications are never generated for table rows that are removed from a view as the result of a collapse operation.

When a row that is defined by a bookmark is collapsed out of view, the bookmark is moved to point to the next visible row.

For more information about categorized tables, see Sorting and Categorization.

See Also

IMAPITable::ExpandRow, IMAPITable::GetCollapseState, IMAPITable::QuerySortOrder, IMAPITable::SetCollapseState, IMAPITable::SortTable, SSortOrderSet


IMAPITable::CreateBookmark

The IMAPITable::CreateBookmark method marks the table's current position.

Quick Info

See IMAPITable : IUnknown.

HRESULT CreateBookmark(
  BOOKMARK FAR * lpbkPosition
);

Parameters

lpbkPosition
[out] Pointer to the returned 32-bit bookmark value. This bookmark can later be passed in a call to the IMAPITable::SeekRow method.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_UNABLE_TO_COMPLETE
The requested operation could not be completed.

Remarks

The IMAPITable::CreateBookmark method marks a table position by creating a value called a bookmark. A bookmark can be used to return to the position identified by the bookmark. The bookmarked position is associated with the object at that row in the table.

Bookmarks are not supported on attachment tables, and attachment table implementations of CreateBookmark return MAPI_E_NO_SUPPORT.

Notes to Implementers

Because of the memory expense of maintaining cursor positions with bookmarks, limit the number of bookmarks that you can create. When you reach that number, return MAPI_E_UNABLE_TO_COMPLETE from all subsequent calls to CreateBookmark.

Sometimes a bookmark points to a row that is no longer in the table view. If a caller uses such a bookmark, move the cursor to the next visible row and stop there.

When the caller attempts to use a bookmark that is pointing to a nonvisible row because it has been collapsed, return MAPI_W_POSITION_CHANGED after moving the bookmark. You can reposition the bookmark to the next visible row either at this time or when the collapsing occurs in the SetCollapseState method. If you move the bookmark at the time the row is collapsed, you must retain a bit in the bookmark that indicates exactly when the bookmark was moved: since its last use or — if it has never been used — since its creation.

Notes to Callers

CreateBookmark allocates memory for the bookmark it creates. Release the resources for the bookmark by calling the IMAPITable::FreeBookmark method.

See Also

IMAPITable::FreeBookmark, IMAPITable::SeekRow


IMAPITable::ExpandRow

The IMAPITable::ExpandRow method expands a collapsed table category, adding the leaf rows belonging to the category to the table view.

Quick Info

See IMAPITable : IUnknown.

HRESULT ExpandRow(
  ULONG cbInstanceKey,
  LPBYTE pbInstanceKey,
  ULONG ulRowCount,
  ULONG ulFlags,
  LPSRowSet FAR * lppRows,
  ULONG FAR * lpulMoreRows
);

Parameters

cbInstanceKey
[in] Count of bytes in the PR_INSTANCE_KEY property pointed to by the pbInstanceKey parameter.
pbInstanceKey
[in] Pointer to the PR_INSTANCE_KEY property that identifies the heading row for the category.
ulRowCount
[in] Maximum number of leaf rows to add to the table view.
ulFlags
Reserved; must be zero.
lppRows
[out] Pointer to an SRowSet structure holding the leaf rows that have been inserted into the table view as a result of the expansion. These rows are inserted after the heading row identified by the pbInstanceKey parameter. The lppRows parameter can be NULL if the ulRowCount parameter is zero.
lpulMoreRows
[out] Pointer to the total number of rows that were added to the table view.

Return Values

S_OK
The category was expanded successfully.
MAPI_E_NOT_FOUND
The row identified by the pbInstanceKey parameter does not exist.

Remarks

The IMAPITable::ExpandRow method expands a collapsed table category, adding the leaf rows that belong to the category to the table view. A limit to the number of rows to be included in the expanded category can be specified in the ulRowCount parameter. When ulRowCount is set to a value greater than zero and one or more rows are returned in the row set pointed to by lppRows, the position of the bookmark BOOKMARK_CURRENT is moved to the row immediately following the last row in the row set.

When ulRowCount is set to zero, requesting that zero leaf rows be added to the category, or zero rows are returned because there are no leaf rows in the category, the position of BOOKMARK_CURRENT is set to the row following the row identified by pbInstanceKey.

Notes to Implementers

Do not generate notifications on rows that are added to a table view due to category expansion.

Notes to Callers

The number of rows in the row set pointed to by the lppRows parameter might not equal the number of rows that were actually added to the table, the entire set of leaf rows for the category. Errors can occur, such as insufficient memory, or the number of rows in the category exceeding the number specified in ulRowCount parameter. In either case, BOOKMARK_CURRENT will be positioned at the last row returned. To immediately retrieve the rest of the rows in the category, call IMAPITable::QueryRows.

Do not expect to receive a table notification when a category changes its state. You can maintain a local cache of rows that can be updated with every ExpandRow or CollapseRow call.

For more information about categorized tables, see Sorting and Categorization.

See Also

IMAPITable::CollapseRow


IMAPITable::FindRow

The IMAPITable::FindRow method finds the next row in a table that matches specific search criteria.

Quick Info

See IMAPITable : IUnknown.

HRESULT FindRow(
  LPSRestriction lpRestriction,
  BOOKMARK BkOrigin,
  ULONG ulFlags
);

Parameters

lpRestriction
[in] Pointer to an SRestriction structure that describes the search criteria.
BkOrigin
[in] Bookmark identifying the row where FindRow should begin its search. A bookmark can be created using the IMAPITable::CreateBookmark method, or one of the following predefined values can be passed:
BOOKMARK_BEGINNING
Searches from the beginning of the table.
BOOKMARK_CURRENT
Searches from the row in the table where the cursor is located.
BOOKMARK_END
Searches from the end of the table.
ulFlags
[in] Bitmask of flags that controls the direction of the search. The following flag can be set:
DIR_BACKWARD
Searches backward from the row identified by the bookmark.

Return Values

S_OK
The find operation was successful.
MAPI_E_INVALID_BOOKMARK
The bookmark in the BkOrigin parameter is invalid because it has been removed or because it is beyond the last row requested.
MAPI_E_NOT_FOUND
No rows were found that matched the restriction.
MAPI_W_POSITION_CHANGED
The call succeeded, but the bookmark used in the operation is no longer set at the same row as when it was last used; if the bookmark has not been used, it is no longer in the same position as when it was created. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IMAPITable::FindRow method locates the first row in the table to match a set of search criteria described in the SRestriction structure pointed to by the lpRestriction parameter.

Usually, FindRow searches forward from the specified bookmark. The caller can set the search to move backward from the bookmark by setting the DIR_BACKWARD flag in the ulFlags parameter. Searching forward starts from the current bookmark; searching backward starts from the row prior to the bookmark. The end position of the search is just before the first row found that satisfied the restriction. FindRow returns the data of the found row.

If the row pointed to by the bookmark in the BkOrigin parameter no longer exists in the table and the table cannot establish a new position for the bookmark, FindRow returns MAPI_E_INVALID_BOOKMARK. If the row pointed to by BkOrigin no longer exists and the table is able to establish a new position for the bookmark, FindRow returns MAPI_W_POSITION_CHANGED.

If the bookmark passed in BkOrigin is either BOOKMARK_BEGINNING or BOOKMARK_END, FindRow returns MAPI_E_NOT_FOUND if no matching row is found. If the bookmark used in BkOrigin is BOOKMARK_CURRENT, FindRow can return MAPI_W_POSITION_CHANGED but not MAPI_E_INVALID_BOOKMARK because there is always a current cursor position.

The PR_INSTANCE_KEY property column is required for all tables, and all implementations of FindRow are required to support calls seeking a row based on PR_INSTANCE_KEY.

Notes to Implementers

The type of prefix searching performed by FindRow is only useful when the search follows the same direction as the table organization. In order to achieve the required behavior, the comparison function implied by the RELOP_GE passed in the property restriction structure should be the same comparison function on which the table sort order is based.

Notes to Callers

You can use FindRow to support scrolling based on strings typed in by the user, especially in list boxes within address dialog boxes. In this type of scrolling, users enter progressively longer prefixes of a desired string value, and you can periodically issue a FindRow call to jump to the first row that matches the prefix. Which direction the cursor jumps depends on which direction the search is set to run.

To use FindRow, a bookmark must be set. The string search can originate from any bookmark, including from the preset bookmarks indicating the current position and the beginning and end of the table. If there is a large number of rows in the table, the search operation can be slow.

Use a restriction to find a string prefix for scrolling as follows. For forward searching on a column sorted in ascending order and for backward searching on a column sorted in descending order, pass a property restriction structure in the lpRestriction parameter with the relation RELOP_GE and the appropriate property tag and prefix, using the format tag GE prefix.

For more information about using restriction structures to specify a filter, see About Restrictions. For information about using regular expressions in restrictions, see Regular Expressions.

See Also

IMAPITable::CreateBookmark, SPropertyRestriction, SRestriction


IMAPITable::FreeBookmark

The IMAPITable::FreeBookmark method releases the memory associated with a bookmark.

Quick Info

See IMAPITable : IUnknown.

HRESULT FreeBookmark(
  BOOKMARK bkPosition
);

Parameters

bkPosition
[in] The bookmark to be freed, created by calling the IMAPITable::CreateBookmark method.

Return Values

S_OK
The bookmark was successfully freed.
MAPI_E_INVALID_BOOKMARK
The specified bookmark does not exist.

Remarks

The IMAPITable::FreeBookmark method releases a bookmark that is no longer needed. The bookmark is no longer valid after this call. Whenever a table is released from memory, all of its associated bookmarks are also released.

Notes to Implementers

If the caller passes one of the three predefined bookmarks in the bkPosition parameter, ignore the request and return S_OK.

See Also

IMAPITable::CreateBookmark


IMAPITable::GetCollapseState

The IMAPITable::GetCollapseState method returns the data necessary to rebuild the current collapsed or expanded state of a categorized table.

Quick Info

See IMAPITable : IUnknown.

HRESULT GetCollapseState(
  ULONG ulFlags,
  ULONG cbInstanceKey,
  LPBYTE lpbInstanceKey,
  ULONG FAR * lpcbCollapseState,
  LPBYTE FAR * lppbCollapseState
);

Parameters

ulFlags
Reserved; must be zero.
cbInstanceKey
[in] Count of bytes in the instance key pointed to by the lpbInstanceKey parameter.
lpbInstanceKey
[in] Pointer to the PR_INSTANCE_KEY property of the row at which the current collapsed or expanded state should be rebuilt. The lpbInstanceKey parameter cannot be NULL.
lpcbCollapseState
[out] Pointer to the count of structures pointed to by the lppbCollapseState parameter.
lppbCollapseState
[out] Pointer to a pointer to structures containing data describing the current table view.

Return Values

S_OK
The state for the categorized table was successfully saved.
MAPI_E_BUSY
Another operation is in progress that prevents the operation from starting. Either the operation in progress should be allowed to complete or it should be stopped.
MAPI_E_NO_SUPPORT
The table does not support categorization and expanded and collapsed views.

Remarks

The IMAPITable::GetCollapseState method works with the IMAPITable::SetCollapseState method to change the user's view of a categorized table. GetCollapseState saves the data necessary for SetCollapseState to use to rebuild the appropriate views of the categories of a categorized table. Service providers determine the data to be saved. However, most service providers implementing GetCollapseState save:

  • The sort keys (standard columns and category columns).
  • Information about the row that the instance key represents.
  • Information to restore the collapsed and expanded categories of the table.

For more information about categorized tables, see Sorting and Categorization.

Notes to Implementers

Store the entire current state of all nodes of a table in the lppbCollapseState parameter.

Notes to Callers

Always call GetCollapseState before calling SetCollapseState.

See Also

IMAPITable::SetCollapseState


IMAPITable::GetLastError

The IMAPITable::GetLastError method returns a MAPIERROR structure containing information about the previous error on the table.

Quick Info

See IMAPITable : IUnknown.

HRESULT GetLastError(
  HRESULT hResult,
  ULONG ulFlags,
  LPMAPIERROR FAR * lppMAPIError
);

Parameters

hResult
[in] HRESULT data type containing the error value generated in the previous method call.
ulFlags
[in] Bitmask of flags that controls the type of the returned strings. The following flag can be set:
MAPI_UNICODE
The strings in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppMAPIError
[out] Pointer to a pointer to the returned MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if a MAPIERROR structure with appropriate information cannot be provided.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Remarks

The IMAPITable::GetLastError method returns detailed information, if available, about a prior method call that failed. This information can be displayed in a message or a dialog box.

Notes to Callers

Call GetLastError whenever you need to display information about an error to the user.

You can make use of the MAPIERROR structure pointed to by the lppMAPIError parameter — if the table object supplies one — only if GetLastError returns S_OK. Sometimes the table implementation cannot determine what the last error was or has nothing more to report about the error. In this situation, you'll find a pointer to NULL in lppMAPIError instead.

To release all the memory allocated for the MAPIERROR structure, call the MAPIFreeBuffer function.

For more information about the GetLastError method, see Using Extended Errors.

See Also

MAPIERROR, MAPIFreeBuffer


IMAPITable::GetRowCount

The IMAPITable::GetRowCount method returns the total number of rows in the table.

Quick Info

See IMAPITable : IUnknown.

HRESULT GetRowCount(
  ULONG ulFlags,
  ULONG FAR * lpulCount
);

Parameters

ulFlags
Reserved; must be zero.
lpulCount
[out] Pointer to the number of rows in the table.

Return Values

S_OK
The row count was successfully returned.
MAPI_E_BUSY
Another operation is in progress that prevents the row count retrieval operation from starting. Either the operation in progress should be allowed to complete or it should be stopped.
MAPI_E_NO_SUPPORT
The table cannot calculate the number of rows.
MAPI_W_APPROX_COUNT
The call succeeded, but an approximate row count was returned because the exact row count could not be determined possibly due to memory constraints. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IMAPITable::GetRowCount method retrieves the total number of rows in a table.

Notes to Implementers

If you cannot determine the table's exact row count, return MAPI_W_APPROX_COUNT and an approximate row count in the contents of the lpulCount parameter.

Notes to Callers

Use GetRowCount to find out how many rows a table holds before making a call to the IMAPITable::QueryRows method to retrieve the data. If there are less than twenty rows in the table, it is safe to call QueryRows to retrieve the whole table. If there are more than twenty rows in the table, consider making multiple calls to QueryRows and limit the number of rows retrieved in each call.

Some tables do not support GetRowCount and return MAPI_E_NO_SUPPORT. If GetRowCount is not supported, an alternative might be to call IMAPITable::QueryPosition. With the results from QueryPosition, you can determine the relationship between the current row and last row.

When GetRowCount returns MAPI_E_BUSY because it is temporarily unable to retrieve a row count, call the IMAPITable::WaitForCompletion method. When WaitForCompletion returns, retry the call to GetRowCount. Another way to detect whether an asynchronous operation is in progress is to call the IMAPITable::GetStatus method and check the contents of the lpulTableState parameter.

See Also

IMAPITable::GetStatus, IMAPITable::QueryPosition, IMAPITable::QueryRows, IMAPITable::WaitForCompletion


IMAPITable::GetStatus

The IMAPITable::GetStatus method returns the table's status and type.

Quick Info

See IMAPITable : IUnknown.

HRESULT GetStatus(
  ULONG FAR * lpulTableStatus,
  ULONG FAR * lpulTableType
);

Parameters

lpulTableStatus
[out] Pointer to a value indicating the status of the table. One of the following values can be returned:
TBLSTAT_COMPLETE
No operations are in progress.
TBLSTAT_QCHANGED
The contents of the table have expectantly changed. This status value is not returned for changes that result from sort or restriction operations.
TBLSTAT_RESTRICT_ERROR
An error occurred during an IMAPITable::Restrict operation.
TBLSTAT_RESTRICTING
An IMAPITable::Restrict operation is in progress.
TBLSTAT_SETCOL_ERROR
An error occurred during an IMAPITable::SetColumns operation.
TBLSTAT_SETTING_COLS
An IMAPITable::SetColumns operation is in progress.
TBLSTAT_SORT_ERROR
An error occurred during an IMAPITable::SortTable operation.
TBLSTAT_SORTING
An IMAPITable::SortTable operation is in progress.
lpulTableType
[out] Pointer to a value that indicates the table's type. One of the following three table types can be returned:
TBLTYPE_DYNAMIC
The table's contents are dynamic; the rows and column values can change as the underlying data changes.
TBLTYPE_KEYSET
The rows within the table are fixed, but the values of the columns within these rows are dynamic and can change as the underlying data changes.
TBLTYPE_SNAPSHOT
The table is static, and its contents do not change when the underlying data changes.

Return Values

S_OK
The table's status was successfully returned.

Remarks

The IMAPTable::GetStatus method retrieves information about a table's type and current status.

Notes to Callers

You can use GetStatus in conjunction with three other IMAPITable methods to monitor the status of those operations and determine the affect on the table. Call GetStatus after making one of the following IMAPITable calls:

  • IMAPITable::Restrict to enforce a restriction.
  • IMAPITable::SortTable to establish a sort order.
  • IMAPITable::SetColumns to define a column set.

See Also

IMAPITable::Restrict, IMAPITable::SetColumns, IMAPITable::SortTable


IMAPITable::QueryColumns

The IMAPITable::QueryColumns method returns a list of columns for the table.

Quick Info

See IMAPITable : IUnknown.

HRESULT QueryColumns(
  ULONG ulFlags,
  LPSPropTagArray FAR * lpPropTagArray
);

Parameters

ulFlags
[in] Bitmask of flags that indicates which column set should be returned. The following flag can be set:
TBL_ALL_COLUMNS
The table should return all available columns.
lpPropTagArray
[out] Pointer to an SPropTagArray structure containing the property tags for the column set.

Return Values

S_OK
The column set was successfully returned.
MAPI_E_BUSY
Another operation is in progress that prevents the column set retrieval operation from starting. Either the operation in progress should be allowed to complete or it should be stopped.

Remarks

The IMAPITable::QueryColumns method can be called to retrieve:

  • The default column set for a table.
  • The current column set for a table, as established by a call to the IMAPITable::SetColumns method.
  • The complete column set for a table, the columns that are available, but not necessarily part of the current set.

Notes to Callers

If you do not set the TBL_ALL_COLUMNS flag, IMAPITable::QueryColumns returns either a table's default or current column set, depending on whether the table has been affected by a call to IMAPITable::SetColumns. SetColumns changes the order and selection of columns in a table's column set.

If you set the TBL_ALL_COLUMNS flag, QueryColumns returns all of the columns that are capable of being in the table's column set.

Free the memory for the property tag array pointed to by the lpPropTagArray parameter by calling the MAPIFreeBuffer function.

See Also

IMAPITable::SetColumns, MAPIFreeBuffer, SPropTagArray


IMAPITable::QueryPosition

The IMAPITable::QueryPosition method retrieves the current table row position of the cursor, based on a fractional value.

Quick Info

See IMAPITable : IUnknown.

HRESULT QueryPosition(
  ULONG FAR * lpulRow,
  ULONG FAR * lpulNumerator,
  ULONG FAR * lpulDenominator
);

Parameters

lpulRow
[out] Pointer to the number of the current row. The row number is zero-based; the first row in the table is zero.
lpulNumerator
[out] Pointer to the numerator for the fraction identifying the table position.
lpulDenominator
[out] Pointer to the denominator for the fraction identifying the table position. The lpulDenominator parameter cannot be zero.

Return Values

S_OK
The method returned valid values in lpulRow, lpulNumerator, and lpulDenominator.

Remarks

The IMAPITable::QueryPosition method determines the current row position and returns both the number of the current row and a fractional value indicating its relative position to the end of the table. MAPI defines the current row as the next row to be read.

Notes to Implementers

You do not need to return the exact number of rows in the table for the lpulDenominator parameter; it can be an approximation.

If you cannot determine the current row, return a value of 0xFFFFFFFF in lpulRow.

Notes to Callers

You can use QueryPosition to position a scroll box in a scroll bar. For example, in a table containing 100 rows, if QueryPosition returns a value of 75 in the lpulNumerator parameter, 100 in the lpulDenominator parameter, and 75 in the lpulRow parameter, you can position the scroll box 3/4 of the way across the scroll bar.

Do not rely on the value in lpulDenominator being the number of rows in the table. QueryPosition cannot always identify the exact row that the cursor is positioned on.

A call to QueryPosition might involve large amounts of memory, particularly for large categorized tables. If the lpulRow parameter is set to 0xFFFFFFFF, too much memory was required for QueryPosition to determine the current row. Call the IMAPITable::SeekRowApprox method to position the table to the row identified by the lpulNumerator and lpulDenominator parameters. However, do not always expect SeekRowApprox to establish as the current position the same row QueryPosition would have if memory had not been a factor.

See Also

IMAPITable::SeekRowApprox


IMAPITable::QueryRows

The IMAPITable::QueryRows method returns one or more rows from a table, beginning at the current cursor position.

Quick Info

See IMAPITable : IUnknown.

HRESULT QueryRows(
  LONG lRowCount,
  ULONG ulFlags,
  LPSRowSet FAR * lppRows
);

Parameters

lRowCount
[in] Maximum number of rows to be returned.
ulFlags
[in] Bitmask of flags that controls how rows are returned. The following flag can be set:
TBL_NOADVANCE
Prevents the cursor from advancing as a result of the row retrieval. If the TBL_NOADVANCE flag is set, the cursor points to the first row returned. If the TBL_NOADVANCE flag is not set, the cursor points to the row following the last row returned.
lppRows
[out] Pointer to a pointer to an SRowSet structure holding the table rows.

Return Values

S_OK
The rows were successfully returned.
MAPI_E_BUSY
Another operation is in progress that prevents the row retrieval operation from starting. Either the operation in progress should be allowed to complete or it should be stopped.
MAPI_E_INVALID_PARAMETER
The lRowCount parameter is set to zero.

Remarks

The IMAPITable::QueryRows method gets one or more rows of data from a table. The value of the lRowCount parameter affects the starting point for the retrieval. If lRowCount is positive, rows are read in a forward direction, starting at the current position. If lRowCount is negative, QueryRows resets the starting point by moving backward the indicated number of rows. After the cursor is reset, rows are read in forward order.

The cRows member in the SRowSet structure pointed to by the lppRows parameter indicates the number of rows returned. If zero rows are returned:

  • The cursor was already positioned at the beginning of the table and the value of IRowCount is negative.

    -Or-

  • The cursor was already positioned at the end of the table and the value of IRowCount is positive.

The number of columns and their ordering is the same for each row. If a property does not exist for a row or there is an error reading a property, the SPropValue structure for the property in the row contains the following values:

  • PT_ERROR for the property type in the ulPropTag member.
  • MAPI_E_NOT_FOUND for the Value member.

Memory used for the SPropValue structures in the row set pointed to by the lppRows parameter must be separately allocated and freed for each row. Use MAPIFreeBuffer to free the property value structures and to free the row set. When a call to QueryRows returns zero, however, indicating the beginning or end of the table, only the SRowSet structure itself needs to be freed. For more information about how to allocate and free memory in an SRowSet structure, see Managing Memory for ADRLIST and SRowSet Structures.

The rows that are returned and the order in which they are returned depend on whether or not successful calls have been made to IMAPITable::Restrict and IMAPITable::SortTable. Restrict filters rows from the view, causing QueryRows to return only the rows that match the criteria specified in the restriction. SortTable establishes a standard or categorized sort order, affecting the sequence of rows returned by QueryRows. The returned rows are in the order specified in the SSortOrderSet structure passed to SortTable.

The columns returned for each row and the order in which they are returned depend on whether or not a successful call has been made to IMAPITable::SetColumns. SetColumns establishes a column set, specifying the properties to be included in columns in the table and the order in which they should be included. If a SetColumns call has been made, the particular columns in each row and the order of those columns match the column set specified in the call. If no SetColumns call has been made, the table returns its default column set.

If none of these calls has been made, QueryRows returns all of the rows in the table. Each row contains the default column set in default order.

When the column set established in a call to IMAPITable::SetColumns includes columns set to PR_NULL, the SPropValue array within the row set returned in lppRows will contain empty slots.

Notes to Implementers

You can allow a caller to request an unsupported column to be included in the column set. When this occurs, place PT_ERROR in the property type portion of the property tag and MAPI_E_NOT_FOUND in the property value for the unsupported column.

Treat the row count as a request rather than a requirement. You can return anywhere from zero rows, if there are no rows in the direction of the query, to the number requested.

Return only the rows that the user will see when rows are requested from a categorized table view, allowing the caller to make valid assumptions about the scope of the data and avoid extra work.

Notes to Callers

Usually you will end up with as many rows as you have specified in the lRowCount parameter. However, when memory or implementation limits are an issue or when the operation reaches the beginning or end of the table prematurely, QueryRows will return less rows than requested.

If QueryRows returns MAPI_E_BUSY, call the IMAPITable::WaitForCompletion method and retry the call to QueryRows when the asynchronous operation is complete.

When calling QueryRows, be aware that the timing of asynchronous notifications can potentially cause the row set that you get back from QueryRows not to accurately represent the underlying data. For example, a call to QueryRows to a folder's contents table following the deletion of a message but prior to the receipt of the corresponding notification will cause the deleted row to be returned in the row set. Always wait for a notification to arrive before updating the user's view of the data.

For more information about retrieving rows from tables, see Retrieving Data from Table Rows.

See Also

ADRENTRY, FreeProws, HrQueryAllRows, IMAPIProp::GetProps, IMAPITable::SetColumns, IMAPITable::WaitForCompletion, MAPIFreeBuffer, SRow, SRowSet


IMAPITable::QuerySortOrder

The IMAPITable::QuerySortOrder method retrieves the current sort order for a table.

Quick Info

See IMAPITable : IUnknown.

HRESULT QuerySortOrder(
  LPSSortOrderSet FAR * lppSortCriteria
);

Parameters

lppSortCriteria
[out] Pointer to a pointer to the SSortOrderSet structure holding the current sort order.

Return Values

S_OK
The current sort order was successfully returned.
MAPI_E_BUSY
Another operation is in progress that prevents the sort order retrieval operation from starting. Either the operation in progress should be allowed to complete or it should be stopped.

Remarks

The IMAPITable::QuerySortOrder method retrieves the current sort order for a table. Sort orders are described with an SSortOrderSet structure.

  • The cSorts member of the SSortOrderSet structure can be set to zero if:
  • The table is unsorted.
  • There is no information about how the table is sorted.
  • The SSortOrderSet structure is not appropriate for describing the sort order.

Notes to Implementers

If a call is made to your IMAPITable::SortTable method with an SSortOrderSet structure containing zero columns in the sort key, remove the current sort order and apply the default order, if there is one. In subsequent calls to QuerySortOrder, you can choose whether to return zero or more columns for the sort key. You can return more columns than are in the present view.

For more information about sorting, see Sorting and Categorization.

See Also

IMAPITable::SortTable, MAPIFreeBuffer, SSortOrderSet


IMAPITable::Restrict

The IMAPITable::Restrict method applies a filter to a table, reducing the row set to only those rows matching the specified criteria.

Quick Info

See IMAPITable : IUnknown.

HRESULT Restrict(
  LPSRestriction lpRestriction,
  ULONG ulFlags
);

Parameters

lpRestriction
[in] Pointer to an SRestriction structure defining the conditions of the filter. Passing NULL in the lpRestriction parameter removes the current filter.
ulFlags
[in] Bitmask of flags that controls the timing of the restriction operation. The following flags can be set:
TBL_ASYNC
Starts the operation asynchronously and returns before the operation completes.
TBL_BATCH
Defers evaluation of the filter until the data in the table is required.

Return Values

S_OK
The filter was successfully applied.
MAPI_E_BUSY
Another operation is in progress that prevents the restriction operation from starting. Either the operation in progress should be allowed to complete or it should be stopped.
MAPI_E_TOO_COMPLEX
The table cannot perform the operation because the particular filter pointed to by the lpRestriction parameter is too complicated.

Remarks

The IMAPITable::Restrict method establishes a restriction, or filter, on a table. If there is a previous restriction, it is discarded and the new one applied. Applying a restriction has no affect on the underlying data of a table; it simply alters the view by limiting the rows that can be retrieved to rows containing data that satisfy the restriction.

There are several different types of restrictions, each described with a different structure. The SRestriction structure contains two members: a value that indicates the type of restriction and the specific structure applicable for that type.

Notifications for table rows that are hidden from view by calls to Restrict are never generated.

A property restriction on a multivalued property works like a restriction on a single-valued property. A multivalued property to be used in a property restriction must have the MVI_FLAG flag set. If it doesn't have this flag set, it is treated as a totally ordered tuple. A comparison of two multivalued columns compares the column elements in order, reporting the relation of the columns at the first inequality. Equality is returned only if the columns compared contain the same values in the same order. If one column has fewer values than the other, the reported relation is that of a null value to the other value.

For more information about restrictions, see About Restrictions.

Notes to Callers

To discard the current restriction without creating a new one, pass NULL in lpRestriction.

If another asynchronous table call is in progress, causing Restrict to return MAPI_E_BUSY, you can call IMAPITable::Abort to stop the call.

Restrict operates synchronously unless you set one of the flags. If you set the TBL_BATCH flag, Restrict postpones the evaluation of the restriction unless you request the data. If the TBL_ASYNC flag is set, Restrict operates asynchronously, potentially returning before the completion of the operation.

All bookmarks for a table are discarded when a call to Restrict is made, and BOOKMARK_CURRENT, the current cursor position, is set to the beginning of the table.

If you attempt to impose a property restriction on a property that is not in the table's column set, the results are undefined. Whenever you are unsure as to whether a property is supported in a table, combine the property restriction with an exists restriction. The exists restriction checks for the existence of the property before attempting to impose the property restriction.

Do not expect to receive a table notification on a row that has been filtered from a table due to a restriction.

See Also

IMAPITable::Abort, IMAPITable::FindRow, IMAPITable::GetRowCount, IMAPITable::QueryRows, SPropertyRestriction


IMAPITable::SeekRow

The IMAPITable::SeekRow method moves the cursor to a specific position in the table.

Quick Info

See IMAPITable : IUnknown.

HRESULT SeekRow(
  BOOKMARK bkOrigin,
  LONG lRowCount,
  LONG FAR * lplRowsSought
);

Parameters

bkOrigin
[in] Bookmark identifying the starting position for the seek operation. A bookmark can be created using the IMAPITable::CreateBookmark method, or one of the following predefined values can be passed:
BOOKMARK_BEGINNING
Starts the seek operation from the beginning of the table.
BOOKMARK_CURRENT
Starts the seek operation from the row in the table where the cursor is located.
BOOKMARK_END
Starts the seek operation from the end of the table.
lRowCount
[in] Signed count of the number of rows to move, starting from the bookmark identified by the bkOrigin parameter.
lplRowsSought
[in-out] If lplRowsSought is a valid pointer on input, on output it points to the number of rows that were processed in the seek operation. If lplRowsSought is NULL on input — indicating that the caller is not interested in the number of rows processed — nothing is returned on output.

Return Values

S_OK
The seek operation was successful.
MAPI_E_BUSY
Another operation is in progress that prevents the row seeking operation from starting. Either the operation in progress should be allowed to complete or it should be stopped.
MAPI_E_INVALID_BOOKMARK
The bookmark specified in the bkOrigin parameter is invalid because it has been removed or because it is beyond the last row requested.
MAPI_W_POSITION_CHANGED
The call succeeded, but the bookmark specified in the bkOrigin parameter is no longer set at the same row as when it was last used. If the bookmark has not been used, it is no longer in the same position as when it was created. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.

Remarks

The IMAPITable::SeekRow method establishes a new BOOKMARK_CURRENT position for the cursor. The lRowCount parameter indicates the number of rows that the cursor moves and the direction of movement.

If the resulting position is beyond the last row of the table, the cursor is positioned after the last row. If the resulting position is before the first row of the table, the cursor is placed at the beginning of the first row.

Notes to Implementers

If the row pointed to by bkOrigin no longer exists in the table and you cannot establish a new position for the bookmark, return MAPI_E_INVALID_BOOKMARK. If the row pointed to by bkOrigin no longer exists and you can establish a new position for the bookmark, return MAPI_W_POSITION_CHANGED.

A bookmark pointing to a row that is collapsed out of the table view can still be used. If the caller attempts to move the cursor to such a bookmark, move the cursor to the next visible row and return MAPI_W_POSITION_CHANGED.

You can move bookmarks for positions collapsed out of view either at the time of use or at the time the row is collapsed. If a bookmark is moved at the time the row is collapsed, keep a bit in the bookmark that indicates whether the bookmark has moved since its last use or, if it has never been used, since its creation.

Notes to Callers

To indicate a backward move for SeekRow, pass a negative value in lRowCount. To search to the beginning of the table, pass zero in lRowCount and the value BOOKMARK_BEGINNING in bkOrigin.

If there are large numbers of rows in the table, the SeekRow operation can be slow. Performance can also be impacted if you require a row count to be returned in the contents of the lplRowsSought parameter.

SeekRow returns the number of rows actually searched through, positive or negative, in the variable pointed to by lplRowsSought. In normal operation, it should return the same value for lplRowsSought as passed in for lRowCount, unless the search reached the beginning or end of the table.

Do not set lRowCount to a number greater than 50. To seek through a larger number of rows, use the IMAPITable::SeekRowApprox method.

See Also

IMAPITable::CreateBookmark, IMAPITable::FindRow, IMAPITable::QueryRows, IMAPITable::SeekRowApprox


IMAPITable::SeekRowApprox

The IMAPITable::SeekRowApprox method moves the cursor to an approximate fractional position in the table.

Quick Info

See IMAPITable : IUnknown.

HRESULT SeekRowApprox(
  ULONG ulNumerator,
  ULONG ulDenominator
);

Parameters

ulNumerator
[in] Pointer to the numerator of the fraction representing the table position. If the ulNumerator parameter is zero, the cursor is positioned at the beginning of the table regardless of the denominator value. If ulNumerator is equal to the ulDenominator parameter, the cursor is positioned after the last table row.
ulDenominator
[in] Pointer to the denominator of the fraction representing the table position. The ulDenominator parameter cannot be zero.

Return Values

S_OK
The seek operation was successful.
MAPI_E_BUSY
Another operation is in progress that prevents the row seeking operation from starting. Either the operation in progress should be allowed to complete or it should be stopped.

Remarks

The cursor position in a table after a call to the IMAPITable::SeekRowApprox method is heuristically the fraction and might not be exact. For example, certain providers might implement a table on top of a binary tree, treating the table's halfway point as the top of the tree for performance reasons. If the tree is not balanced, then the halfway point used might not be exactly halfway through the table.

Notes to Callers

Call SeekRowApprox to provide the data for a scroll bar implementation. For example, if the user positions the scroll box 2/3 down the scroll bar, you can model that action by calling SeekRowApprox and passing in an equivalent fractional value using ulNumerator and ulDenominator. The SeekRowApprox search is always absolute from the beginning of the table. To move to the end of the table, the values in ulNumerator and ulDenominator must be the same.

Use whatever number scheme is appropriate. That is, to seek to a position halfway through the table, you can specify 1/2, 10/20, or 50/100.


IMAPITable::SetCollapseState

The IMAPITable::SetCollapseState method rebuilds the current expanded or collapsed state of a categorized table using data that was saved by a prior call to the IMAPITable::GetCollapseState method.

Quick Info

See IMAPITable : IUnknown.

HRESULT SetCollapseState(
  ULONG ulFlags,
  ULONG cbCollapseState,
  LPBYTE pbCollapseState,
  BOOKMARK FAR * lpbkLocation
);

Parameters

ulFlags
Reserved; must be zero.
cbCollapseState
[in] Count of bytes in the structure pointed to by the pbCollapseState parameter.
pbCollapseState
[in] Pointer to the structures containing the data needed to rebuild the table view.
lpbkLocation
[out] Pointer to a bookmark identifying the row in the table at which the collapsed or expanded state should be rebuilt. This bookmark and the instance key passed in the lpbInstanceKey parameter in the call to IMAPITable::GetCollapseState identify the same row.

Return Values

S_OK
The state of the categorized table was successfully rebuilt.
MAPI_E_BUSY
Another operation is in progress that prevents the operation from starting. Either the operation in progress should be allowed to complete or it should be stopped.
MAPI_E_UNABLE_TO_COMPLETE
The table could not finish rebuilding the collapsed or expanded view.

Remarks

The IMAPITable::SetCollapseState method reestablishes the expanded or collapsed state of the table view. SetCollapseState and GetCollapseState work together as follows:

  1. When the state of a categorized table is about to change, IMAPITable::GetCollapseState is called to save all of the data pertaining to the state prior to the change.
  2. To restore the view of the table to its saved state, SetCollapseState is called. The data saved by GetCollapseState is passed to SetCollapseState. SetCollapseState is able to use that data to restore the state.
  3. SetCollapseState returns as an output parameter a bookmark that identifies the same row as the instance key passed as input to GetCollapseState.

For more information about categorized tables, see Sorting and Categorization.

Notes to Implementers

You are responsible for verifying that the sort order and restrictions are exactly the same as they were at the time of the GetCollapseState call. If a change has been made, ideally SetCollapseState should not be called because the results can be unpredictable. This can happen if, for example, a client calls GetCollapseState and then SortTable to change the sort key before calling SetCollapseState. To be safe, check that the saved data is still valid before proceeding with the restoration.

Notes to Callers

To call SetCollapseState, you must have previously called GetCollapseState. The sort order establishing the categories should be the same for both methods. If the sort orders differ, the results of the SetCollapseState operation are unpredictable.

See Also

IMAPITable::CreateBookmark, IMAPITable::FreeBookmark, IMAPITable::GetCollapseState


IMAPITable::SetColumns

The IMAPITable::SetColumns method defines the particular properties and order of properties to appear as columns in the table.

Quick Info

See IMAPITable : IUnknown.

HRESULT SetColumns(
  LPSPropTagArray lpPropTagArray,
  ULONG ulFlags
);

Parameters

lpPropTagArray
[in] Pointer to an array of property tags identifying properties to be included as columns in the table. The property type portion of each tag can be set to a valid type or to PR_NULL to reserve space for subsequent additions. The lpPropTagArray parameter cannot be set to NULL; every table must have at least one column.
ulFlags
[in] Bitmask of flags that controls the return of an asynchronous call to SetColumns, for example when SetColumns is used in notification. The following flags can be set:
TBL_ASYNC
Requests that the column setting operation be performed asynchronously causing SetColumns to potentially return before the operation has fully completed.
TBL_BATCH
Permits the table to postpone the column setting operation until the data is actually required.

Return Values

S_OK
The column setting operation was successful.
MAPI_E_BUSY
Another operation is in progress that prevents the column setting operation from starting. Either the operation in progress should be allowed to complete or it should be stopped.

Remarks

The column set of a table is the group of properties that make up the columns for the rows in the table. There is a default column set for each type of table. The default column set is made up of the properties that the table implementer automatically includes. Table users can alter this default set by calling the IMAPITable::SetColumns method. They can request that other columns be added to the default set — if the table implementer supports them — that columns be removed, or that the order of columns be changed. SetColumns specifies the columns that are returned with each row and the order of these columns within the row.

The success of the SetColumns operation is apparent only after a subsequent call has been made to retrieve the data of the table. It is then that any errors are reported.

Notes to Implementers

Some providers allow a SetColumns call to order only table columns that are part of the available columns for a table view. Other providers allow a SetColumns call to order all table columns, including those containing properties not in the original column set.

When TBL_BATCH is set for asynchronous operations, providers should return a property type of PT_ERROR and a property value of NULL for columns that are not supported.

You do not need to respond to the TBL_ASYNC flag requesting that the operation be asynchronous. If you do not support asynchronous column set definition, perform the operation synchronously. If you can support the TBL_ASYNC flag and another asynchronous operation is still in progress, return MAPI_E_BUSY. Otherwise, return S_OK regardless of whether or not you support all of the properties included in the property tag array. Errors resulting from unsupported properties should be returned from IMAPITable methods that retrieve data, such as QueryRows.

Do not generate notifications for table rows that are hidden from view by calls to Restrict.

When sending table notifications, the order of the properties in the row member of the TABLE_NOTIFICATION structure and the order specified by the most recent SetColumns call must be the same as of the time that the notification request was sent.

Another flag, TBL_BATCH, allows callers to specify that the table implementer can defer evaluating the results of the operation until a later time. Whenever possible, callers should set this flag because batched operation improves performance.

It is often convenient for callers to reserve some columns in the retrieved row set for values to be added later. Callers do this by placing PR_NULL at the desired positions in the property tag array passed to SetColumns; the table will then pass back PR_NULL at those positions in all rows retrieved with QueryRows.

Notes to Callers

When building the property tag array for the lpPropTagArray parameter, order the tags in the order that you want the columns to appear in the table view.

You can specify multivalued properties to be included in the column set by applying the multivalued instance flag, or MVI_FLAG constant, to the property tag. Set this flag by passing the property tag for the single-valued version of the property as a parameter to the MVI_PROP macro as follows:

MVI_PROP(ulPropTag)

The MVI_PROP macro will set MVI_FLAG for the property, turning the tag into a multivalued tag. If you erroneously try to call MVI_PROP on a single-valued property, MAPI will ignore the call and leave the property tag unchanged.

You can include property tags set to PR_NULL in the property tag array to reserve space in the column set. Reserving space allows you to add to a column set without having to allocate a new property tag array.

When your call to SetColumns causes a change to the order of a table's columns and one or more of these columns represent a multivalued property, it is possible for the number of rows in the table to increase. If this occurs, all of the bookmarks for the table are discarded. For more information about how multivalued columns affect tables, see Working with Multivalued Columns.

Setting columns is by default a synchronous operation. However, you can allow the table to postpone the operation until such time as the data is needed by setting the TBL_BATCH flag. Setting this flag can improve performance. Another flag, TBL_ASYNC, makes the operation asynchronous, allowing SetColumns to return before the operation is complete. To determine when completion occurs, call IMAPITable::GetStatus.

If a call to SetColumns returns MAPI_E_BUSY, indicating that another operation is preventing your operation from starting, you can call IMAPITable::Abort to stop the operation in progress.

You can also call HrAddColumnsEx to change a column set. The difference between HrAddColumnsEx and IMAPITable::SetColumns is that HrAddColumnsEx is less flexible; it can only add columns. The additional columns are placed at the beginning of the column set; all existing columns appear following these columns.

See Also

HrQueryAllRows, imapiTable::abort, IMAPITable::GetRowCount, IMAPITable::QueryColumns, IMAPITable::QueryRows, IMAPITable::Restrict, IMAPITable::SortTable, SPropTagArray, SPropValue, SRowSet, TABLE_NOTIFICATION


IMAPITable::SortTable

The IMAPITable::SortTable method orders the rows of the table based on sort criteria.

Quick Info

See IMAPITable : IUnknown.

HRESULT SortTable(
  LPSSortOrderSet lpSortCriteria,
  ULONG ulFlags
);

Parameters

lpSortCriteria
[in] Pointer to an SSortOrderSet structure containing the sort criteria to apply. Passing an SSortOrderSet structure containing zero columns indicates that the table does not need to be sorted in any particular order.
ulFlags
[in] Bitmask of flags that controls the timing of the IMAPITable::SortTable operation. The following flags can be set:
TBL_ASYNC
Starts the operation asynchronously and returns before the operation completes.
TBL_BATCH
Defers the completion of the sort until the data in the table is required.

Return Values

S_OK
The sort operation was successful.
MAPI_E_BUSY
Another operation is in progress that prevents the sort operation from starting. Either the operation in progress should be allowed to complete or it should be stopped.
MAPI_E_NO_SUPPORT
The table does not support the type of sorting requested.
MAPI_E_TOO_COMPLEX
The table cannot perform the operation because the particular sort criteria pointed to by the lpSortCriteria parameter is too complicated. SortTable can return MAPI_E_TOO_COMPLEX when:
  • A sort operation is requested for a property column that the implementation cannot sort.
  • The implementation does not support the sort order requested in the ulOrder member of the SSortOrderSet structure.
  • The number of columns to be sorted, as specified in the cSorts member in SSortOrderSet, is larger than the implementation can handle.
  • A sort operation is requested, as indicated by a property tag in SSortOrderSet, based on a property that is not in the available or active set and the implementation does not support sorting on properties not in the available set.
  • One property is specified multiple times in a sort order set, as indicated by multiple instances of the same property tag, and the implementation cannot perform such a sort operation.
  • A sort operation based on multivalued property columns is requested using MVI_FLAG and the implementation does not support sorting on multivalued properties.
  • A property tag for a property in SSortOrderSet specifies a property or type that the implementation does not support.
  • A sort operation other than one that proceeds through the table from the PR_RENDERING_POSITION property forward is specified only for an attachment table that supports this type of sorting.

Remarks

The IMAPITable::SortTable method orders the rows in a table view. Whereas some tables support both standard and categorized sorting on a variety of sort key columns, other tables are more limited in their support. Address book providers commonly do not support table sorting. Message store providers commonly support sorting to the extent that they retain the sort order of folders that results when a full table — that is, a table with no restrictions — is sorted.

Some tables allow sorting to be done on any table column. Other tables do not; columns not included in the table view are unaffected by a SortOrder call. Some tables require that sort keys be built only with columns in the table's current column set.

A table will return either MAPI_E_NO_SUPPORT or MAPI_E_TOO_COMPLEX from SortTable when it cannot complete a sort operation for whatever reason.

When there are zero columns in the SSortOrderSet structure pointed to by the lpSortCriteria parameter, the table returns the current column set. The current sort order can be retrieved by calling the table's IMAPITable::QuerySortOrder method.

All bookmarks for a table are invalidated and should be deleted when a call to SortTable is made, and the BOOKMARK_CURRENT bookmark, indicating the current cursor position, should be set to the beginning of the table.

If sorting on a column containing a multivalued property without the MVI_FLAG flag set, the column's values are treated as a totally ordered tuple. A comparison of two multivalued columns compares the column elements in order, reporting the relation of the columns at the first inequality, and returns equality only if the columns compared contain the same values in the same order. If one column has fewer values than the other, the reported relation is that of a null value to the other value.

Notes to Callers

SortTable operates synchronously unless you set one of the flags. If you set the TBL_BATCH flag, SortTable postpones the sort operation unless you request the data. If the TBL_ASYNC flag is set, SortTable operates asynchronously, potentially returning before the completion of the operation.

Call the IMAPITable::Abort method to stop an asynchronous operation in progress if your sort must be done immediately. If SortTable cannot proceed because one or more asynchronous operations on the table are in progress, it returns MAPI_E_BUSY.

For best performance, call SetColumns to customize the table's column set and Restrict to limit the number of rows in the table before calling SortTable to perform the sort.

Whenever SortTable fails, the sort order that was in effect before the failure is still in effect.

See Also

IMAPITable::Abort, IMAPITable::GetRowCount, IMAPITable::QueryColumns, IMAPITable::QuerySortOrder, IMAPITable::SetColumns, SSortOrderSet


IMAPITable::Unadvise

The IMAPITable::Unadvise method cancels the sending of notifications previously set up with a call to the IMAPITable::Advise method.

Quick Info

See IMAPITable : IUnknown.

HRESULT Unadvise(
  ULONG ulConnection
);

Parameters

ulConnection
[in] Number of the registration connection returned by a call to IMAPITable::Advise.

Return Value

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Use the IMAPITable::Unadvise method to release the pointer to the advise sink object passed in the lpAdviseSink parameter in the previous call to IMAPITable::Advise, thereby canceling a notification registration. As part of discarding the pointer to the advise sink object, the object's IUnknown::Release method is called. Generally, Release is called during the Unadvise call, but if another thread is in the process of calling the IMAPIAdviseSink::OnNotify method for the advise sink, the Release call is delayed until the OnNotify method returns.

For more information on the notification process, see Event Notification in MAPI. For specific information about table notification, see About Table Notifications. For information about using the IMAPISupport methods to support notification, see Supporting Event Notification.

See Also

IMAPIAdviseSink::OnNotify, IMAPITable::Advise


IMAPITable::WaitForCompletion

The IMAPITable::WaitForCompletion method suspends processing until one or more asynchronous operations in progress on the table have completed.

Quick Info

See IMAPITable : IUnknown.

HRESULT WaitForCompletion(
  ULONG ulFlags,
  ULONG ulTimeout,
  ULONG FAR * lpulTableStatus
);

Parameters

ulFlags
Reserved; must be zero.
ulTimeout
[in] Maximum number of milliseconds to wait for the asynchronous operation or operations to complete. To wait indefinitely until completion occurs, set ulTimeout to 0xFFFFFFFF.
lpulTableStatus
[in-out] On input, either a valid pointer or NULL. On output, if lpulTableStatus is a valid pointer, it points to the most recent status of the table. If lpulTableStatus is NULL, no status information is returned. If WaitForCompletion returns a nonzero HRESULT value, the contents of lpulTableStatus are undefined.

Return Values

S_OK
The wait operation was successful.
MAPI_E_NO_SUPPORT
The table does not support waiting for the completion of asynchronous operations.
MAPI_E_TIMEOUT
The asynchronous operation or operations did not complete in the specified time.

Remarks

The IMAPITable::WaitForCompletion method suspends processing until any asynchronous operations currently under way for the table have completed. WaitForCompletion can allow the asynchronous operations either to fully complete or to run for a certain number of milliseconds, as indicated by ulTimeout, before being interrupted. To detect asynchronous operations in progress, call the IMAPITable::GetStatus method.

See Also

IMAPITable::GetRowCount, IMAPITable::GetStatus, IMAPITable::Restrict, IMAPITable::SetColumns, IMAPITable::SortTable


IMAPIViewAdviseSink : IUnknown

The IMAPIViewAdviseSink interface is used by form viewers to receive notifications from forms.

Quick Info

Header file: | MAPIFORM.H
Exposed by: | View advise sink objects
Implemented by: | Form viewers
Called by: | Form objects
Interface identifier: | IID_IMAPIViewAdviseSink
Pointer type: | LPMAPIVIEWADVISESINK

Vtable Order

OnShutdown | Notifies the form viewer that a form is being closed.
OnNewMessage | Notifies the form viewer that either a new or an existing message has been loaded in a form.
OnPrint | Notifies the form viewer of the printing status of a form.
OnSubmitted | Notifies the form viewer that the current message has been submitted to the MAPI spooler.
OnSaved | Notifies the form viewer that the current message in a form has been saved.


IMAPIViewAdviseSink::OnShutdown

The IMAPIViewAdviseSink::OnShutdown method notifies the form viewer that a form is being closed.

Quick Info

See IMAPIViewAdviseSink : IUnknown.

HRESULT OnShutdown();

Parameters

None

Return Values

S_OK
The notification succeeded.

Remarks

For more information about form notifications, see Sending and Receiving Form Notifications.


IMAPIViewAdviseSink::OnNewMessage

The IMAPIViewAdviseSink::OnNewMessage method notifies the form viewer that either a new or an existing message has been loaded in a form.

Quick Info

See IMAPIViewAdviseSink : IUnknown.

HRESULT OnNewMessage();

Parameters

None

Return Values

S_OK
The notification succeeded.

Remarks

Form objects call the IMAPIViewAdviseSink::OnNewMessage method whenever a message is loaded in a form using either the IPersistMessage::InitNew or IPersistMessage::Load method.

Notes to Implementers

Release your active pointer to the form object because it no longer points to the message your viewer was formerly viewing.

For more information about form notifications, see Sending and Receiving Form Notifications.

See Also

IMAPIForm : IUnknown, IPersistMessage::InitNew, IPersistMessage::Load


IMAPIViewAdviseSink::OnPrint

The IMAPIViewAdviseSink::OnPrint method notifies the form viewer of the printing status of a form.

Quick Info

See IMAPIViewAdviseSink : IUnknown.

HRESULT OnPrint(
  ULONG dwPageNumber,
  HRESULT hrStatus
);

Parameters

dwPageNumber
[in] Number of the last page printed.
hrStatus
[in] An HRESULT value indicating the status of the print job. Possible values are:
S_FALSE
The printing job has finished successfully.
S_OK
The printing job is in progress.
FAILED
The printing job was terminated due to a failure.

Return Values

S_OK
The notification succeeded.
MAPI_E_USER_CANCEL
The user canceled the operation, typically by clicking the Cancel button in a dialog box.

Remarks

Form objects call the IMAPIViewAdviseSink::OnPrint method while printing to inform the viewer of printing progress.

Notes to Callers

If the printing job involves multiple pages, you can call OnPrint after each page is printed. Set dwPageNumber to the page currently being printed and hrStatus to S_OK. When the printing job is complete, call OnPrint with dwPageNumber set to the last page printed and hrStatus set to S_FALSE.

For more information about form notifications, see Sending and Receiving Form Notifications.


IMAPIViewAdviseSink::OnSaved

The IMAPIViewAdviseSink::OnSaved method notifies the form viewer that the current message in a form has been saved.

Quick Info

See IMAPIViewAdviseSink : IUnknown.

HRESULT OnSaved();

Parameters

None

Return Value

S_OK
The call succeeded and has returned the expected value or values.

Remarks

A form object calls the IMAPIViewAdviseSink::OnSaved method after the current message in a form has been successfully saved. Doing so permits viewers to update their windows to reflect changes to the message.

For more information about form notifications, see Sending and Receiving Form Notifications.


IMAPIViewAdviseSink::OnSubmitted

The IMAPIViewAdviseSink::OnSubmitted method notifies the form viewer that the current message has been submitted to the MAPI spooler.

Quick Info

See IMAPIViewAdviseSink : IUnknown.

HRESULT OnSubmitted();

Parameters

None

Return Value

S_OK
The notification succeeded.

Remarks

A form object calls the IMAPIViewAdviseSink::OnSubmitted method after its call to IMAPIMessageSite::SubmitMessage has returned successfully.

Notes to Implementers

After OnSubmitted is called, you can continue on the assumption that the message has been updated. Update your windows to reflect any changes that have occurred.

For more information about form notifications, see Sending and Receiving Form Notifications.

See Also

IMAPIMessageSite::SubmitMessage


IMAPIViewContext : IUnknown

The IMAPIViewContext interface manages a form in a client application's form viewer.

Quick Info

Header file: | MAPIFORM.H
Exposed by: | View context objects
Implemented by: | Form viewers
Called by: | Form objects
Interface identifier: | IID_IMAPIViewContext
Pointer type: | LPMAPIVIEWCONTEXT

Vtable Order

SetAdviseSink | Manages a form's registration to receive notifications about changes in the viewer.
ActivateNext | Activates the next or previous message in the form viewer.
GetPrintSetup | Retrieves current printing information.
GetSaveStream | Retrieves a stream to be used for saving the current message.
GetViewStatus | Retrieves the current viewer status.


IMAPIViewContext::ActivateNext

The IMAPIViewContext::ActivateNext method activates the next or previous message in the view order.

Quick Info

See IMAPIViewContext : IUnknown.

HRESULT ActivateNext(
  ULONG ulDir,
  LPCRECT prcPosRect
);

Parameters

ulDir
[in] Status flags giving information about the message to be activated. Valid flag settings are:
VCDIR_CATEGORY
The viewer should activate a message in another category of the view. The message to be activated is:
· The first message in the next view category if this flag is ORed with VCDIR_NEXT.
· The last message in the previous view category if this flag is ORed with VCDIR_PREV and the previous category is expanded.
· The first message in the previous view category if this flag is ORed with VCDIR_PREV and the previous category is not expanded. In this case the previous category undergoes automatic expansion.
VCDIR_DELETE
The viewer should activate the next or previous message because the current message has been deleted.
VCDIR_MOVE
The viewer should activate the next or previous message because the current message has been moved.
VCDIR_NEXT
The viewer should activate the next message in the view order.
VCDIR_PREV
The viewer should activate the previous message in the view order.
VCDIR_UNREAD
The viewer should activate the next or previous unread message in the view order.
prcPosRect
[in] Pointer to a Windows RECT structure containing the size and position of the window to be used to display the activated message.

Return Values

S_OK
The message was activated successfully.
S_FALSE
The message was activated successfully, but a different type of form was opened in the process.

Remarks

Form objects call the IMAPIViewContext::ActivateNext method to change what message is displayed to the user. The value passed in the ulDir parameter indicates which message should be activated and, in some cases, why. The VCDIR_NEXT and VCDIR_PREVIOUS flags correspond to users choosing the Next or Previous command in a view, respectively. These operations usually correspond to moving up or down one message in the form viewer's list of messages.

The VCDIR_DELETE and VCDIR_MOVE flags are set by the IMAPIMessageSite::DeleteMessage and IMAPIMessageSite::MoveMessage methods, respectively. Implementations of these methods call ActivateNext with the appropriate direction and then perform the requested operation on the message if the ActivateNext call did not fail. Form viewers typically enable users to specify the direction to move in the message list.

Notes to Implementers

Your implementation of IMAPIViewContext::ActivateNext makes the next or previous message in the folder, depending on the value of ulDir, the current message. After ActivateNext returns, call IMAPIMessageSite::GetMessage to get a pointer to the newly activated message.

Notes to Callers

If ActivateNext returns S_FALSE, or if a current message is not present, perform your normal shutdown procedure which should include calling your form's IMAPIForm::ShutdownForm method. If a next or previous message is displayed, use the window rectangle passed in the prcPosRect parameter to display it.

See Also

IMAPIViewContext::GetViewStatus


IMAPIViewContext::GetPrintSetup

The IMAPIViewContext::GetPrintSetup method retrieves current printing information.

Quick Info

See IMAPIViewContext : IUnknown.

HRESULT GetPrintSetup(
  ULONG ulFlags,
  LPFORMPRINTSETUP FAR * lppFormPrintSetup
);

Parameters

ulFlags
[in] Bitmask of flags that controls the type of the returned strings. The following flag can be set:
MAPI_UNICODE
The returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppFormPrintSetup
[out] Pointer to a pointer to a structure that holds the printing information.

Return Value

S_OK
The printing information was successfully retrieved.

Remarks

Form objects call the IMAPIViewContext::GetPrintSetup method to retrieve information about the printer setup before attempting to print the current message.

Notes to Implementers

Allocate the hDevMode and hDevNames members of the FORMPRINTSETUP structure using the Win32 function GlobalAlloc.

Notes to Callers

If you expect the hDevMode and hDevName members of the FORMPRINTSETUP structure pointed to by the lppFormPrintSetup parameter to be Unicode strings, set ulFlags to MAPI_UNICODE. Otherwise, GetPrintSetup will return these strings in ANSI format.

Free the hDevMode and hDevName members of the FORMPRINTSETUP structure by calling the Win32 function GlobalFree. Free the entire FORMPRINTSETUP structure by calling MAPIFreeBuffer.

See Also

FORMPRINTSETUP


IMAPIViewContext::GetSaveStream

The IMAPIViewContext::GetSaveStream method retrieves a stream to be used for saving the current message.

Quick Info

See IMAPIViewContext : IUnknown.

HRESULT GetSaveStream(
  ULONG FAR * pulFlags,
  ULONG FAR * pulFormat,
  LPSTREAM FAR * ppstm
);

Parameters

pulFlags
[out] Pointer to a bitmask of flags that controls how the message text should be saved. The following flag can be set:
MAPI_UNICODE
The message text is saved in Unicode format. If the MAPI_UNICODE flag is not set, the text is saved in ANSI format.
pulFormat
[out] Pointer to a bitmask of flags that controls the format of the saved text. The following flags can be set:
SAVE_FORMAT_RICHTEXT
The message text is to be saved as formatted text in the Rich Text Format (RTF).
SAVE_FORMAT_TEXT
The message text is to be saved as plain text.
ppstm
[out] Pointer to a pointer to the stream that will contain the saved message.

Return Value

S_OK
The stream was successfully retrieved.

Remarks

Form objects call the IMAPIViewContext::GetSaveStream method to retrieve a stream — an object that implements the IStream interface — to support the handling of the Save As verb in the form viewer. The IMAPIForm::DoVerb method, which is implemented in the form server and called by the form viewer to invoke a verb, should not return until the message is fully converted into the appropriate text format and placed into the appropriate stream.

Notes to Callers

Do not write to the stream pointed to by ppstm before calling GetSaveStream. When GetSaveStream returns, do not reset the position of the seek pointer. This pointer must remain at the end of the saved message text.


IMAPIViewContext::GetViewStatus

The IMAPIViewContext::GetViewStatus method retrieves the current viewer status.

Quick Info

See IMAPIViewContext : IUnknown.

HRESULT GetViewStatus(
  ULONG FAR * lpulStatus
);

Parameter

lpulStatus
[out] Pointer to a bitmask of flags providing the status of the viewer. The following flags can be set:
VCSTATUS_CATEGORY
There is a next or previous message in another category.
VCSTATUS_DELETE
The form allows messages to be removed.
VCSTATUS_INTERACTIVE
The form should display a user interface. If this flag is not set, the form should suppress displaying a user interface even in response to a verb that usually causes a user interface to be displayed.
VCSTATUS_MODAL
The form is modal to the viewer.
VCSTATUS_NEXT
There is a next message in the view.
VCSTATUS_PREV
There is a previous message in the view.
VCSTATUS_READONLY
The message is to be opened in read-only mode. Delete, submit, and move operations should be disabled.
VCSTATUS_UNREAD
There is a next or previous unread message in the view.

Return Value

S_OK
The viewer's status was successfully returned.

Remarks

Form objects call the IMAPIViewContext::GetViewStatus method to determine whether there are more messages to be activated in a form view in either or both directions — that is, in the direction in which a Next command activates messages, in the direction in which a Previous command activates messages, or in both directions. The value pointed to by the lpulStatus parameter is used to determine whether the VCSTATUS_NEXT and VCSTATUS_PREV flags are valid for IMAPIViewContext::ActivateNext. If the VCSTATUS_DELETE flag is set, but not the VCSTATUS_READONLY flag, then the message can be deleted using the IMAPIMessageSite::DeleteMessage method.

Typically, forms disable menu commands and buttons if they are not valid for the viewer's context. A viewer can alert a form to a change in status by calling its IMAPIFormAdviseSink::OnChange method.

The VCSTATUS_MODAL flag is set if the form must be modal to the window whose handle is passed in the earlier IMAPIForm::DoVerb call. If VCSTATUS_MODAL is set, the form can use the thread on which the DoVerb call was made until the form closes. If VCSTATUS_MODAL is not set, the form should not be modal to this window and must not use the thread.

See Also

IMAPIMessageSite::GetSiteStatus


IMAPIViewContext::SetAdviseSink

The IMAPIViewContext::SetAdviseSink method manages a form's registration to receive notifications about changes in the viewer.

Quick Info

See IMAPIViewContext : IUnknown.

HRESULT SetAdviseSink(
  LPMAPIFORMADVISESINK pmvns
);

Parameters

pmvns
[in] Pointer to a form advise sink object or NULL.

Return Value

S_OK
The registration or cancellation for form notification succeeded.

Remarks

Form objects call the IMAPIViewContext::SetAdviseSink method to either register to learn about changes in the form viewer or cancel a prior registration. When pmvns is set to NULL, the form wants to cancel a registration. When pmvns points to a valid form advise sink, the form wants to register for future notifications.

Notes to Implementers

When SetAdviseSink includes a form advise sink pointer, keep a reference to it until another SetAdviseSink call is made to cancel notification. Send a notification when a change occurs in your viewer and when you are loading a new message.

For more information, see Sending and Receiving Form Notifications.


IMessage : IMAPIProp

The IMessage interface is used for managing messages, attachments, and recipients.

Quick Info

Header file: | MAPIDEFS.H
Exposed by: | Message object
Implemented by: | Message store providers
Called by: | Client applications
Interface identifier: | IID_IMessage
Pointer type: | LPMESSAGE
Transaction model: | Transacted

Vtable Order

GetAttachmentTable | Returns the message's attachment table.
OpenAttach | Opens an attachment.
CreateAttach | Creates a new attachment.
DeleteAttach | Deletes an attachment.
GetRecipientTable | Returns the message's recipient table.
ModifyRecipients | Adds, deletes, or modifies message recipients.
SubmitMessage | Saves all changes to the message and marks it as ready for sending.
SetReadFlag | Sets or clears the MSGFLAG_READ flag in the PR_MESSAGE_FLAGS property of the message and manages the sending of read reports.

The following properties are required on messages at some point during their lifecycle. Most of the read-only properties are set by the message store provider when a client calls a message's IMAPIProp::SaveChanges method. Other read-only properties are set by the transport provider.

Required properties for messages of all classes | Access
PR_CREATION_TIME | Read-only
PR_DISPLAY_BCC | Read-only
PR_DISPLAY_CC | Read-only
PR_DISPLAY_TO | Read-only
PR_ENTRYID | Read-only
PR_LAST_MODIFICATION_TIME | Read-only
PR_MESSAGE_ATTACHMENTS | Read-only
PR_MESSAGE_CLASS | Read/write
PR_MESSAGE_FLAGS | Read/write
PR_MESSAGE_RECIPIENTS | Read-only
PR_MESSAGE_SIZE | Read-only
PR_MESSAGE_CC_ME | Read-only
PR_MESSAGE_RECIP_ME | Read-only
PR_MESSAGE_TO_ME | Read-only
PR_NORMALIZED_SUBJECT | Read-only
PR_ORIGINATOR properties | Read-only
PR_PARENT_DISPLAY | Read-only
PR_PARENT_ENTRYID | Read-only
PR_RECEIVED_BY properties | Read-only
PR_RECIPIENT_TYPE | Read-only
PR_RECORD_KEY | Read-only
PR_SEARCH_KEY | Read-only
PR_SENDER properties | Read-only
PR_STORE_ENTRYID | Read-only
PR_STORE_RECORD_KEY | Read-only

The following properties are all read-only to clients, with the exception of PR_BODY. Clients construct this property when they process a report.

Properties for report messages
PR_BODY
PR_CONVERSATION_INDEX
PR_CONVERSATION_TOPIC
PR_MESSAGE_CLASS
PR_MESSAGE_DELIVERY_TIME
PR_ORIGINAL_DELIVERY_TIME
PR_ORIGINAL_DISPLAY_BCC
PR_ORIGINAL_DISPLAY_CC
PR_ORIGINAL_DISPLAY_TO
PR_ORIGINAL_SUBJECT
PR_ORIGINAL_SUBMIT_TIME
PR_REPORT_TAG
PR_REPORT_TEXT
PR_REPORT_TIME
PR_SEARCH_KEY
PR_SENDER properties
PR_SUBJECT

Properties for message recipients | Access | Required or optional
PR_ADDRTYPE | Read-only | Required
PR_DISPLAY_NAME | Read/write | Required
PR_DISPLAY_TYPE | Read/write | Required
PR_EMAIL_ADDRESS | Read-only | Optional
PR_ENTRYID | Read-only | Required
PR_OBJECT_TYPE | Read-only | Required
PR_SEARCH_KEY | Read-only | Optional


IMessage::CreateAttach

The IMessage::CreateAttach method creates a new attachment.

Quick Info

See IMessage : IMAPIProp.

HRESULT CreateAttach(
  LPCIID lpInterface,
  ULONG ulFlags,
  ULONG FAR * lpulAttachmentNum,
  LPATTACH FAR * lppAttach
);

Parameters

lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the message. Passing NULL results in the message's standard interface, or IMessage, being returned.
ulFlags
[in] Bitmask of flags that controls how the attachment is created. The following flag can be set:
MAPI_DEFERRED_ERRORS
Allows CreateAttach to return successfully, possibly before the attachment is fully accessible to the calling client. If the attachment is not accessible, making a subsequent call to it can result in an error.
lpulAttachmentNum
[out] Pointer to an index number identifying the newly created attachment. This number is valid only when the message is open and is the basis for the attachment's PR_ATTACH_NUM property.
lppAttach
[out] Pointer to a pointer to the open attachment object.

Return Value

S_OK
The attachment was successfully created.

Remarks

The IMessage::CreateAttach method creates a new attachment within a message. The new attachment and any properties that are set for it are not available until a client has called the attachment's IMAPIProp::SaveChanges method and the message's IMAPIProp::SaveChanges method. Both the attachment and its message have to be saved before the attachment is included in the message's attachment table.

The attachment number pointed to by lpulAttachmentNum is unique and valid only within the context of the message. That is, two attachments in two different messages can have the same number while two attachments in the same message cannot.


IMessage::DeleteAttach

The IMessage::DeleteAttach method deletes an attachment.

Quick Info

See IMessage : IMAPIProp.

HRESULT DeleteAttach(
  ULONG ulAttachmentNum,
  ULONG ulUIParam,
  LPMAPIPROGRESS lpProgress,
  ULONG ulFlags
);

Parameters

ulAttachmentNum
[in] Index number of the attachment to delete. This is the value for the attachment's PR_ATTACH_NUM property.
ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays. The ulUIParam parameter is ignored unless the ATTACH_DIALOG flag is set in the ulFlags parameter.
lpProgress
[in] Pointer to a progress object for displaying a progress indicator. If NULL is passed in lpProgress, the message store provider displays a progress indicator using the MAPI progress object implementation. The lpProgress parameter is ignored unless the ATTACH_DIALOG flag is set in ulFlags.
ulFlags
[in] Bitmask of flags that controls the display of a user interface. The following flag can be set:
ATTACH_DIALOG
Requests the display of a progress indicator as the operation proceeds.

Return Value

S_OK
The attachment was successfully deleted.

Remarks

The IMessage::DeleteAttach method deletes an attachment from within a message.

A deleted attachment is not permanently deleted until the message's IMAPIProp::SaveChanges method has been called.

Notes to Callers

Before calling DeleteAttach, call the IUnknown::Release method for the attachment and each of its streams.

Because deleting an attachment can be a lengthy process, DeleteAttach provides the mechanism for displaying a progress indicator. You can request the display of a progress indicator by passing a pointer to your IMAPIProgress : IUnknown implementation or NULL if you do not have an implementation. You must also specify a window handle in the ulUIParam parameter and the ATTACH_DIALOG flag in the ulFlags parameter.

See Also

IMAPIProp::SaveChanges


IMessage::GetAttachmentTable

The IMessage::GetAttachmentTable method returns the message's attachment table.

Quick Info

See IMessage : IMAPIProp.

HRESULT GetAttachmentTable(
  ULONG ulFlags,
  LPMAPITABLE FAR * lppTable
);

Parameters

ulFlags
[in] Bitmask of flags that relate to the creation of the table. The following flag can be set:
MAPI_UNICODE
The string columns are in Unicode format. If the MAPI_UNICODE flag is not set, the string columns are in ANSI format.
MAPI_DEFERRED_ERRORS
Allows GetAttachmentTable to return successfully, possibly before the table is fully accessible to the calling client. If the table is not accessible, making a subsequent call to it can result in an error.
lppTable
[out] Pointer to a pointer to the attachment table.

Return Values

S_OK
The attachment table was successfully retrieved.

Remarks

The IMessage::GetAttachmentTable method returns a pointer to the message's attachment table, which includes information about all of the attachments in the message. Clients can get access to an attachment only through the attachment table. By retrieving an attachment's number — its PR_ATTACH_NUM property — a client can use several of the IMessage methods to work with the attachment.

There is one row for each attachment. For a complete list of the columns in an attachment table, see Attachment Tables.

An attachment usually does not appear in the attachment table until both the attachment and the message have been saved with a call to IMAPIProp::SaveChanges. Attachment tables are dynamic. If a client creates a new attachment, deletes an existing attachment, or changes one or more properties once the SaveChanges calls have been made on the attachment on the message, the attachment table will be updated to reflect the new information.

Some attachment tables support a wide variety of restrictions; others do not. Support for restrictions depends on the message store provider's implementation.

When initially opened, attachment tables are not necessarily sorted in any particular order.

Setting the MAPI_UNICODE flag in the ulFlags parameter affects the following calls to the attachment table:

  • IMAPITable::QueryColumns to retrieve the column set.
  • IMAPITable::QueryRows to retrieve rows.
  • IMAPITable::QuerySortOrder to retrieve the sort order.

Setting the Unicode flag requests that the information for any string columns returned from these calls be in Unicode format. However, because not all message store providers support Unicode, setting this flag is only a request.

See Also

IMessage::CreateAttach, IMessage::DeleteAttach, IMessage::OpenAttach


IMessage::GetRecipientTable

The IMessage::GetRecipientTable method returns the message's recipient table.

Quick Info

See IMessage : IMAPIProp.

HRESULT GetRecipientTable(
  ULONG ulFlags,
  LPMAPITABLE FAR * lppTable
)

Parameters

ulFlags
[in] Bitmask of flags that controls the return of the table. The following flags can be set:
MAPI_DEFERRED_ERRORS
Allows GetRecipientTable to return successfully, possibly before the table is fully accessible to the calling client. If the table is not accessible, making a subsequent call to it can result in an error.
MAPI_UNICODE
The string columns should be in Unicode format. If the MAPI_UNICODE flag is not set, the string columns should be in ANSI format.
lppTable
[out] Pointer to a pointer to the recipient table.

Return Value

S_OK
The recipient table was returned successfully.

Remarks

The IMessage::GetAttachmentTable method returns a pointer to the message's recipient table, which includes information about all of the recipients for the message. There is one for every recipient.

Recipient tables have a different column set depending on whether the message has been submitted. For a complete list of the columns in a recipient table, see Recipient Tables.

Some recipient tables support a wide variety of restrictions; others do not. Support for restrictions depends on the message store provider's implementation.

Setting the MAPI_UNICODE flag in the ulFlags parameter affects the following calls to the recipient table:

  • IMAPITable::QueryColumns to retrieve the column set.
  • IMAPITable::QueryRows to retrieve rows.
  • IMAPITable::QuerySortOrder to retrieve the sort order.

Setting the Unicode flag requests that the information for any string columns returned from these calls be in Unicode format. However, because not all message store providers support Unicode, setting this flag is only a request.

Notes to Callers

You can change a recipient table while it is open by calling the IMessage::ModifyRecipients method. ModifyRecipients adds recipients, deletes recipients, or modifies recipient properties.

See Also

IMAPIProp::SaveChanges, IMAPITable::QueryRows, IMessage::ModifyRecipients


IMessage::ModifyRecipients

The IMessage::ModifyRecipients method adds, deletes, or modifies message recipients.

Quick Info

See IMessage : IMAPIProp.

HRESULT ModifyRecipients(
  ULONG ulFlags,
  LPADRLIST lpMods
);

Parameters

ulFlags
[in] Bitmask of flags that controls the recipient changes. If zero is passed for the ulFlags parameter, ModifyRecipients replaces all existing recipients with the recipient list pointed to by the lpMods parameter. The following flags can be set for ulFlags:
MODRECIP_ADD
The recipients pointed to by the lpMods parameter should be added to the recipient list.
MODRECIP_MODIFY
The recipients pointed to by the lpMods parameter should replace existing recipients. All of the existing properties are replaced by those in the corresponding ADRENTRY structure.
MODRECIP_REMOVE
Existing recipients should be removed from the recipient list using as an index the PR_ROWID property included in the property value array of each recipient entry in the lpMods parameter.
lpMods
[in] Pointer to an ADRLIST structure containing a list of recipients to be added, deleted, or modified in the message.

Return Value

S_OK
The recipient list was successfully modified.

Remarks

The IMessage::ModifyRecipients method changes the message's recipient list. It is from this list, held in an ADRLIST structure, that the recipient table is built.

The ADRLIST structure contains one ADRENTRY structure for each recipient and each ADRENTRY structure contains an array of property values describing the recipient properties.

Recipients in the ADRLIST structure can be resolved or unresolved. The difference is in the number and type of properties that are included. An unresolved recipient contains only the PR_DISPLAY_NAME and PR_RECIPIENT_TYPE properties while a resolved recipient contains those two properties plus PR_ADDRTYPE and PR_ENTRYID. If PR_EMAIL_ADDRESS is available, it can be included also.

By the time a message is submitted, it must include only resolved recipients in its recipient list. Unresolved recipients cause nondelivery reports to be created and sent to the original sender of the message. For more information about the name resolution process from the client perspective, see Resolving a Name. For more information from the perspective of the address book provider, see Implementing Name Resolution.

In addition to resolved and unresolved recipients, a recipient can be NULL. That is, the cValues member of the ADRENTRY structure for the recipient is set to zero and the rgPropVals member is set to NULL.

Notes to Callers

You can create a recipient list by calling IAddrBook::Address to display the common dialog box and prompt the user to select entries. The address list pointed to by the lppAdrList parameter to Address can be passed to ModifyRecipients as the lpMods parameter.

When you specify properties for a recipient in the ADRLIST structure, include all of the recipient's properties, not only the new or changed ones. When a recipient is modified, any properties not included in the ADRLIST structure are deleted. To retrieve the current set of properties for all of a message's recipients, call GetRecipientTable and retrieve all of the rows. Because an SRowSet is identical in structure to an ADRLIST, you can use them interchangeably.

ModifyRecipients replaces all of the entries in the current recipient list with the information pointed to by lpMods when none of the flags are set in the ulFlags parameter.

Notes to Callers

When you set the MODRECIP_MODIFY flag, ModifyRecipients replaces each entire recipient row with the associated row in the ADRLIST structure passed in lpMods. Be careful to specify all of the properties that a recipient should have regardless of whether they have changed to prevent them from being unintentionally deleted.

Following are some rules for setting the properties of the recipients in the ADRLIST structure:

  • Do not use PT_NULL as a property type. ModifyRecipients returns an error when encountering this value.
  • Do not use PT_ERROR as a property type. ModifyRecipients ignores this value.
  • Include the PR_ROWID property for all recipients when you set either the MODRECIP_REMOVE or MODRECIP_MODIFY flag in ulFlags.
  • Do not include the PR_ROWID property for any of the recipients when you set the MODRECIP_ADD flag in ulFlags or when you pass zero in ulFlags.

If you include either the PR_ADDRTYPE property or PR_EMAIL_ADDRESS property for a recipient and one or both of these properties are inconsistent with the address type and address of the recipient as identified by PR_ENTRYID, the results are undefined. That is, there are three possibilities, depending on the service provider:

  • The message will be delivered to the address described by the PR_ADDRTYPE and PR_EMAIL_ADDRESS properties.
  • The message will be delivered to the recipient identified by PR_ENTRYID.
  • The message will be declared undeliverable due to the ambiguity of the address information.

Use the allocation rules outlined in Managing Memory for ADRLIST and SRowSet Structures to allocate memory for the recipient list. ModifyRecipients does not free the ADRLIST structure nor any of its substructures. The ADRLIST structure and each SPropValue structure must be separately allocated by using the MAPIAllocateBuffer function such that each can be freed individually. If the method requires additional space for any SPropValue structure, it can replace the SPropValue structure with a new one that can later be freed using MAPIFreeBuffer. The original SPropValue structure should also be freed using MAPIFreeBuffer.

See Also

ADRENTRY, ADRLIST, IAddrBook::Address, IMAPISupport::Address, MAPIAllocateBuffer, MAPIFreeBuffer, SPropValue


IMessage::OpenAttach

The IMessage::OpenAttach method opens an attachment.

Quick Info

See IMessage : IMAPIProp.

HRESULT OpenAttach(
  ULONG ulAttachmentNum,
  LPCIID lpInterface,
  ULONG ulFlags,
  LPATTACH FAR * lppAttach
);

Parameters

ulAttachmentNum
[in] Index number of the attachment to open, as stored in the attachment's PR_ATTACH_NUM property. This index number uniquely identifies the attachment in the message and is valid only in the context of the message.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the attachment. Passing NULL results in the attachment's standard interface, or IAttach, being returned.
ulFlags
[in] Bitmask of flags that controls how the attachment is opened. The following flags can be set:
MAPI_BEST_ACCESS
Requests that the attachment be opened with the maximum network permissions allowed for the user and the maximum client application access. For example, if the client has read/write access, the attachment should be opened with read/write access; if the client has read-only access, the attachment should be opened with read-only access.
MAPI_DEFERRED_ERRORS
Allows OpenAttach to return successfully, possibly before the attachment is fully accessible to the calling client. If the attachment is not accessible, making a subsequent call to it can result in an error.
MAPI_MODIFY
Requests read/write access. By default, attachments are opened with read-only access, and clients should not work on the assumption that read/write access has been granted.
lppAttach
[out] Pointer to a pointer to the open attachment.

Return Value

S_OK
The attachment was successfully opened.

Remarks

The IMessage::OpenAttach method opens a message's attachment.

Notes to Callers

To open an attachment, you must have access to its attachment number — or PR_ATTACH_NUM property. Call IMessage::GetAttachmentTable to retrieve the message's attachment table and locate the row that represents the attachment to be opened. See Opening an Attachment for more information.

Do not try to open one attachment multiple times; the results are undefined and dependent on the message store provider.

You can request that the attachment be opened in read/write mode, rather than the default read-only mode. However, whether or not the attachment will actually be opened in read/write mode is up to the message store provider. You can either attempt to modify the attachment, preparing to handle possible failure, or check the level of access that was granted by retrieving the attachment's PR_ACCESS_LEVEL property, if it is available.


IMessage::SetReadFlag

The IMessage::SetReadFlag method sets or clears the MSGFLAG_READ flag in the PR_MESSAGE_FLAGS property of the message and manages the sending of read reports.

Quick Info

See IMessage : IMAPIProp.

HRESULT SetReadFlag(
  ULONG ulFlags
);

Parameters

ulFlags
[in] Bitmask of flags that controls the setting of a message's read flag — that is, the message's MSGFLAG_READ flag in its PR_MESSAGE_FLAGS property — and the processing of read reports. The following flags can be set:
CLEAR_READ_FLAG
The MSGFLAG_READ flag should be cleared in PR_MESSAGE_FLAGS and no read report should be sent.
CLEAR_NRN_PENDING
The MSGFLAG_NRN_PENDING flag should be cleared in PR_MESSAGE_FLAGS and a nonread report should not be sent.
CLEAR_RN_PENDING
The MSGFLAG_RN_PENDING flag should be cleared in PR_MESSAGE_FLAGS and no read report should be sent.
GENERATE_RECEIPT_ONLY
A read report should be sent if one is pending, but there should be no change in the state of the MSGFLAG_READ flag.
MAPI_DEFERRED_ERRORS
Allows SetReadFlag to return successfully, possibly before the operation has completed.
SUPPRESS_RECEIPT
A pending read report should be canceled if a read report had been requested and this call changes the state of the message from unread to read. If this call does not change the state of the message, the message store provider can ignore this flag.

Return Values

S_OK
The message's read flag has been successfully set or cleared.
MAPI_E_NO_SUPPRESS
The message store provider does not support the suppression of read reports.
MAPI_E_INVALID_PARAMETER
One of the following combinations of flags is set in the ulFlags parameter:
  • SUPPRESS_RECEIPT | CLEAR_READ_FLAG
  • SUPPRESS_RECEIPT | CLEAR_READ_FLAG | GENERATE_RECEIPT_ONLY
  • CLEAR_READ_FLAG | GENERATE_RECEIPT_ONLY

Remarks

The IMessage::SetReadFlag method sets or clears the message's MSGFLAG_READ flag in the PR_MESSAGE_FLAGS property and calls IMAPIProp::SaveChanges to save the message. Setting the MSGFLAG_READ flag marks a message as having been read, which does not necessarily indicate that the intended recipient has actually read the message.

SetReadFlags also manages the sending of read reports. A read report is sent only if the sender has requested one.

The read flag cannot be altered for:

  • Messages that do not exist.
  • Messages that have been moved elsewhere.
  • Messages that are open with read/write access.
  • Messages that are currently submitted.

Notes to Implementers

If none of the flags are set in the ulFlags parameter, the following rules apply:

  • If MSGFLAG_READ is already set, do nothing.
  • If MSGFLAG_READ is not set, set it immediately and send any pending read reports if the PR_READ_RECEIPT_REQUESTED property is set.

If both the SUPPRESS_RECEIPT and GENERATE_RECEIPT_ONLY flags are set, the PR_READ_RECEIPT_REQUESTED bit, if set, should be cleared and a read report should not be sent.

When the SUPPRESS_RECEIPT flag is set:

  • If MSGFLAG_READ is already set, do nothing.
  • If MSGFLAG_READ is not set, set it and cancel any pending read reports.

When the CLEAR_READ_FLAG flag is set, clear the MSGFLAG_READ flag in each message's PR_MESSAGE_FLAGS property and do not send any read reports.

When the GENERATE_RECEIPT_ONLY flag is set, send any pending read reports. Do not set or clear MSGFLAG_READ.

When both the SUPPRESS_RECEIPT and GENERATE_RECEIPT_ONLY flags are set, set the PR_READ_RECEIPT_REQUESTED property to FALSE if it is set and do not send a read report.

You can optimize report behavior by suppressing the generation of read reports under certain conditions. However, if you do not support the suppression of reports and a client calls SetReadFlag with the SUPPRESS_RECEIPT flag set, return MAPI_E_NO_SUPPRESS.

See Also

IMAPIContainer::OpenEntry, IMAPIFolder::SetReadFlags, IMAPIProp::GetProps, IMAPIProp::SaveChanges, PR_MESSAGE_FLAGS


IMessage::SubmitMessage

The IMessage::SubmitMessage method saves all of the message's properties and marks the message as ready to be sent.

Quick Info

See IMessage : IMAPIProp.

HRESULT SubmitMessage(
  ULONG ulFlags
);

Parameters

ulFlags
[in] Bitmask of flags used to control how a message is submitted. The following flag can be set:
FORCE_SUBMIT
MAPI should submit the message immediately. This flag is not currently in use.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_NO_RECIPIENTS
The message's recipient table is empty.

Remarks

The IMessage::SubmitMessage method marks a message as ready to be transmitted. MAPI passes messages to the underlying messaging system in the order in which they are marked for sending. Because of this functionality, a message might stay in a message store for some time before the underlying messaging system can take responsibility for it. The order of receipt at the destination is in the underlying messaging system's control and does not necessarily match the order in which messages were sent.

Notes to Implementers

Call the message's IMAPIProp::SaveChanges method to save it and then check the message's PR_MESSAGE_FLAGS property. If the MSGFLAG_RESEND flag is set, call IMAPISupport::PrepareSubmit. PrepareSubmit updates the recipient type and PR_RESPONSIBILITY property for all of the recipients in the resend message.

Notes to Callers

When SubmitMessage returns, all pointers to the message and its associated subobjects — messages, folders, attachments, streams, tables, and so on — are no longer valid. MAPI does not permit any further operations on these pointers, except for calling their IUnknown::Release methods. MAPI is designed such that after SubmitMessage is called, you should release the message and all associated subobjects. However, if SubmitMessage returns an error value indicating missing or invalid information, the message remains open and the pointers remain valid.

To cancel a send operation, get and store a pointer to the message's PR_ENTRYID property before the message is submitted. Because a message's entry identifier is invalidated after the message has been submitted, it is necessary to save it before calling SubmitMessage. To cancel the send, point the lpEntryId parameter to this entry identifier and call IMsgStore::AbortSubmit.

See Also

IMsgStore::AbortSubmit


IMsgServiceAdmin : IUnknown

The IMsgServiceAdmin interface is used to make changes to a message service within a profile.

Quick Info

Header file: | MAPIX.H
Exposed by: | Message service administration objects
Implemented by: | MAPI
Called by: | Client applications
Interface identifier: | IID_IMsgServiceAdmin
Pointer type: | LPSERVICEADMIN

Vtable Order

GetLastError | Returns a MAPIERROR structure containing information about the last error that occurred for a message service administration object.
GetMsgServiceTable | Provides access to the message service's provider table, a listing of the message services in the profile.
CreateMsgService | Adds a message service to the current profile.
DeleteMsgService | Deletes a message service from a profile.
CopyMsgService | Copies a message service into a profile.
RenameMsgService | Assigns a new name to a message service.
ConfigureMsgService | Enables a user to reconfigure a message service using the service's configuration property sheet.
OpenProfileSection | Opens a section of the current profile and returns an IProfSect pointer for further access
MsgServiceTransportOrder | Sets the order in which transport providers are called to deliver a message.
AdminProviders | Returns a pointer providing access to a provider administration object.
SetPrimaryIdentity | Designates a message service to be the supplier of the primary identity for the profile.
GetProviderTable | Provides access to the provider table, a listing of the service providers in the profile.

Remarks

An implementation can get a pointer to an IMsgServiceAdmin interface in two ways: by calling the IMAPISession::AdminServices method or by calling the IProfAdmin::AdminServices method. For clients primarily concerned with profile configuration — for example, control panels — IProfAdmin::AdminServices is the preferred way to get the IMsgServiceAdmin interface because it does not log providers on to the MAPI session. If a client requires the ability to make changes to the active profile, then IMAPISession::AdminServices should be called to get the IMsgServiceAdmin pointer. Clients that are modifying the profile that is active for the session should be designed with the awareness that although MAPI does not allow a profile that is in use to be deleted, there are no safeguards to prevent a client from removing all the message services within the profile.


IMsgServiceAdmin::AdminProviders

The IMsgServiceAdmin::AdminProviders method returns a pointer providing access to a provider administration object.

Quick Info

See IMsgServiceAdmin : IUnknown.

HRESULT AdminProviders(
  LPMAPIUID lpUID,
  ULONG ulFlags,
  LPPROVIDERADMIN FAR * lppProviderAdmin
);

Parameters

lpUID
[in] Pointer to the MAPIUID structure holding the unique identifier for the message service to be administered.
ulFlags
[in] Bitmask of flags that controls the type of the passed-in string. The following flag can be set:
MAPI_UNICODE
The passed-in string is in Unicode format. If the MAPI_UNICODE flag is not set, the string is in ANSI format.
lppProviderAdmin
[out] Pointer to a pointer to a provider administration object.

Return Values

S_OK
The provider administration object was successfully returned.
MAPI_E_NOT_FOUND
The MAPIUID pointed to by lpUID does not exist.

Remarks

The IMsgServiceAdmin::AdminProviders method provides access to a provider administration object. A provider administration object — an object that supports the IProviderAdmin interface — allows clients to add service providers to a message service, delete service providers from a message service, open profile sections, and access the message service provider table.

The types of changes that can actually be made to a message service while the profile is in use depend on the message service. However, most message services do not support changes such as adding and deleting providers while the profile is in use.

Notes to Callers

To retrieve the MAPIUID for the message service to administer, retrieve the PR_SERVICE_UID column from the message service's row in the message service table. See the procedure outlined in IMsgServiceAdmin::CreateMsgService for more information.

See Also

IProviderAdmin : IUnknown, MAPIUID


IMsgServiceAdmin::ConfigureMsgService

The IMsgServiceAdmin::ConfigureMsgService method reconfigures a message service.

Quick Info

See IMsgServiceAdmin : IUnknown.

HRESULT ConfigureMsgService(
  LPMAPIUID lpUID,
  ULONG ulUIParam,
  ULONG ulFlags,
  ULONG cValues,
  LPSPropValue lpProps
);

Parameters

lpUID
[in] Pointer to the MAPIUID structure holding the unique identifier for the message service to configure.
ulUIParam
[in] Handle of the parent window for the configuration property sheet.
ulFlags
[in] Bitmask of flags that controls the display of the property sheet. The following flags can be set:
MAPI_UNICODE
The passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
MSG_SERVICE_UI_READ_ONLY
The message service should display its configuration property sheet but not enable the user to change it. Most message services ignore this flag.
SERVICE_UI_ALLOWED
The message service should display its configuration property sheet only if the service is not completely configured.
SERVICE_UI_ALWAYS
The message service must always display its configuration property sheet. If SERVICE_UI_ALWAYS is not set, a configuration property sheet can still be displayed if SERVICE_UI_ALLOWED is set and valid configuration information is not available from the property value array in the lpProps parameter. Either SERVICE_UI_ALLOWED or SERVICE_UI_ALWAYS must be set for a property sheet to be displayed.
cValues
[in] Count of property values in the SPropValue structure pointed to by lpProps.
lpProps
[in] Pointer to an array of property values describing the properties to display in the property sheet. The lpProps parameter should not be NULL if the message service should be configured without a user interface.

Return Values

S_OK
The message service was successfully configured.
MAPI_E_EXTENDED_ERROR
An error specific to a message service. To get the MAPIERROR structure describing the error, the client application should call the IMsgServiceAdmin::GetLastError method.
MAPI_E_NOT_FOUND
The MAPIUID pointed to by lpUID does not match that of an existing message service.
MAPI_E_NOT_INITIALIZED
The message service does not have an entry point function.
MAPI_E_USER_CANCEL
The user canceled the operation, typically by clicking the Cancel button in the property sheet.

Remarks

The IMsgServiceAdmin::ConfigureMsgService method allows a message service to be configured, with or without a configuration property sheet.

To allow configuration without a property sheet display, message services typically prepare a header file that includes constants for all the required and optional properties and their values.

Notes to Callers

To retrieve the MAPIUID for the message service to configure, retrieve the PR_SERVICE_UID column from the message service's row in the message service table. See the procedure outlined in IMsgServiceAdmin::CreateMsgService for more information.

You can configure a message service without displaying a property sheet to a user only if you have advance information about the property values to be set. If you are configuring a message service without displaying a property sheet, pass valid property values in the lpProps parameter and do not set the MSG_SERVICE_UI_READ_ONLY, SERVICE_UI_ALLOWED, or SERVICE_UI_ALWAYS flags.

If you receive all or some of the configuration information from the user by way of a property sheet, set SERVICE_UI_ALLOWED in ulFlags. If you use existing property information only to establish default settings and the user is able to change the settings, set SERVICE_UI_ALWAYS in ulFlags.

See Also

MAPIUID, SPropValue


IMsgServiceAdmin::CopyMsgService

The IMsgServiceAdmin::CopyMsgService method copies a message service into a profile.

Quick Info

See IMsgServiceAdmin : IUnknown.

HRESULT CopyMsgService(
  LPMAPIUID lpUID,
  LPTSTR lpszDisplayName,
  LPCIID lpInterfaceToCopy,
  LPCIID lpInterfaceDst,
  LPVOID lpObjectDst,
  ULONG ulUIParam,
  ULONG ulFlags
);

Parameters

lpUID
[in] Pointer to the MAPIUID structure holding the unique identifier of the message service to copy.
lpszDisplayName
[in] Pointer to the display name of the message service to copy.
lpInterfaceToCopy
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the profile section of the message service to copy. Passing NULL results in the standard profile section interface, IProfSect, being used.
lpInterfaceDst
[in] Pointer to the IID representing the interface to be used to access the object pointed to by the lpObjectDst parameter. Passing NULL results in the session interface, IMAPISession, being used. The lpInterfaceDst parameter can also be set to IID_IMsgServiceAdmin.
lpObjectDst
[in] Pointer to a pointer to a session or message service administration object. The type of object should correspond to the interface identifier passed in lpInterfaceDst. Valid object pointers are LPMAPISESSION and LPSERVICEADMIN.
ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays.
ulFlags
[in] Bitmask of flags that controls how the message service is copied. The following flags can be set:
MAPI_UNICODE
The display name of the message service is in Unicode format. If the MAPI_UNICODE flag is not set, the display name is in ANSI format.
SERVICE_UI_ALWAYS
Requests that the message service always display a configuration property sheet.

Return Values

S_OK
The message service was successfully copied.
MAPI_E_NO_ACCESS
The message service is already in the profile and does not allow multiple instances of itself.
MAPI_E_NOT_FOUND
The MAPIUID pointed to by lpUID does not refer to an existing message service.

Remarks

The IMsgServiceAdmin::CopyMsgService method copies a message service into a profile, either the active profile or another profile. The profile containing the message service to be copied and the destination do not have to be the same profile, but they can be.

The message service's entry point function is not called for a copy operation. The copied message service has the same configuration settings as its original. To change these settings, a client should call the IMsgServiceAdmin::ConfigureMsgService method.

See Also

IMsgServiceAdmin::ConfigureMsgService, MAPIUID


IMsgServiceAdmin::CreateMsgService

The IMsgServiceAdmin::CreateMsgService method adds a message service to the current profile.

Quick Info

See IMsgServiceAdmin : IUnknown.

HRESULT CreateMsgService(
  LPTSTR lpszService,
  LPTSTR lpszDisplayName,
  ULONG ulUIParam,
  ULONG ulFlags
);

Parameters

lpszService
[in] Pointer to the name of the message service to add. This message service name must appear in the [Services] section of the MAPISVC.INF file.
lpszDisplayName
[in] Pointer to the display name of the message service to add. The lpszDisplayName parameter is ignored if the message service has set PR_DISPLAY_NAME in the MAPISVC.INF file.
ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays.
ulFlags
[in] Bitmask of flags that controls how the message service is installed. The following flags can be set:
MAPI_UNICODE
The names are in Unicode format. If the MAPI_UNICODE flag is not set, the names are in ANSI format.
SERVICE_UI_ALLOWED
Allows the display of the message service's configuration property sheet only if the service is not completely configured.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_NOT_FOUND
The message service name is not in the [Services] section of MAPISVC.INF.

Remarks

The IMsgServiceAdmin::CreateMsgService method adds a message service to the current profile. CreateMsgService calls the message service's entry point function to perform any service-specific configuration tasks. If the SERVICE_UI_ALLOWED flag is set in the ulFlags parameter, the message service being installed can display a property sheet to enable the user to configure its settings.

The list of providers that make up a message service and the properties for each are contained within the MAPISVC.INF file. CreateMsgService first creates a new profile section for the message service and then copies all of the information for that service from the MAPISVC.INF file into the profile, creating new sections for each provider.

After all the information has been copied from MAPISVC.INF, the message service's entry point function is called with the MSG_SERVICE_CREATE value set in the ulContext parameter. If the SERVICE_UI_ALLOWED flag is set in the CreateMsgService method's ulFlags parameter, then the values in the CreateMsgService ulUIParam and ulFlags parameters are also passed when the message service's entry point function is called. Service providers should display their configuration property sheets so users can configure the message service.

Notes to Callers

CreateMsgService does not return the MAPIUID for the message service added to the profile.

To retrieve the MAPIUID for the created message service
  1. Call IMsgServiceAdmin::GetMsgServiceTable to get the message service administration table.
  2. Locate the row that represents the message service by placing a restriction on the table that matches the PR_SERVICE_NAME property with the name of the message service.
  3. Retrieve the service's PR_SERVICE_UID property.
  4. Pass the value of the PR_SERVICE_UID property in the lpUid parameter to IMsgServiceAdmin::ConfigureMsgService to configure the service.


IMsgServiceAdmin::DeleteMsgService

The IMsgServiceAdmin::DeleteMsgService method deletes a message service from a profile.

Quick Info

See IMsgServiceAdmin : IUnknown.

HRESULT DeleteMsgService(
  LPMAPIUID lpuid
);

Parameters

lpuid
[in] Pointer to the MAPIUID structure holding the unique identifier for the message service to delete.

Return Values

S_OK
The message service was deleted.
MAPI_E_NOT_FOUND
The MAPIUID pointed to by lpuid does not match an existing message service.

Remarks

The IMsgServiceAdmin::DeleteMsgService method deletes a message service from a profile. DeleteMsgService removes all profile sections related to the message service.

DeleteMsgService performs the following steps to delete the message service:

  1. Calls the message service's entry point function with the ulContext parameter set to MSG_SERVICE_DELETE before the profile sections are removed. This allows the service to perform any service-specific tasks.
  2. Deletes the message service.
  3. Deletes the message service's profile section.

The message service's entry point function is not called again after the service has been deleted.

Notes to Callers

To retrieve the MAPIUID for the message service to delete, retrieve the PR_SERVICE_UID column from the message service's row in the message service table. See the procedure outlined in IMsgServiceAdmin::CreateMsgService for more information.

See Also

MAPIUID


IMsgServiceAdmin::GetLastError

The IMsgServiceAdmin::GetLastError method returns a MAPIERROR structure containing information about the last error that occurred for a message service administration object.

Quick Info

See IMsgServiceAdmin : IUnknown.

HRESULT GetLastError(
  HRESULT hResult,
  ULONG ulFlags,
  LPMAPIERROR FAR * lppMAPIError
);

Parameters

hResult
[in] HRESULT data type containing the error value generated by the previous method call.
ulFlags
[in] Bitmask of flags that controls the type of the returned strings. The following flag can be set:
MAPI_UNICODE
The strings in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppMAPIError
[out] Pointer to a pointer to the returned MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_BAD_CHARWIDTH
The MAPI_UNICODE flag was set and the message service administration object does not support Unicode.

Remarks

The IMsgServiceAdmin::GetLastError method retrieves information about the last error that was returned by an IMsgServiceAdmin method call. Clients can provide their users with detailed information about the error by including this information in a dialog box.

Notes to Callers

You can make use of the MAPIERROR structure pointed to by the lppMAPIError parameter, if MAPI supplies one, only if GetLastError returns S_OK. Sometimes MAPI cannot determine what the last error was or has nothing more to report about the error. In this situation, GetLastError returns a pointer to NULL in lppMAPIError instead.

For more information about the GetLastError method, see Using Extended Errors.

See Also

MAPIERROR, MAPIFreeBuffer


IMsgServiceAdmin::GetMsgServiceTable

The IMsgServiceAdmin::GetMsgServiceTable method provides access to the message service table, a listing of the message services in the profile.

Quick Info

See IMsgServiceAdmin : IUnknown.

HRESULT GetMsgServiceTable(
  ULONG ulFlags,
  LPMAPITABLE FAR * lppTable
);

Parameters

ulFlags
[in] Bitmask of flags that controls the type of the string columns in the table. The following flag can be set:
MAPI_UNICODE
The string columns are in Unicode format. If the MAPI_UNICODE flag is not set, the string columns are in ANSI format.
lppTable
[out] Pointer to a pointer to the message service table.

Return Value

S_OK
The message service table was successfully returned.

Remarks

The IMsgServiceAdmin::GetMsgServiceTable method provides access to the message service table, a table maintained by MAPI that lists the message services currently installed in the session profile.

For a complete list of columns in the message service table, see Message Service Table.

The message service table is static. After a client has been given access to it, subsequent message service additions or deletions will not affect it.

If there are no message services in the current profile, GetMsgServiceTable returns a table with zero rows.

Setting the MAPI_UNICODE flag in the ulFlags parameter affects the format of the columns returned from the following IMAPITable methods:

IMAPITable::QueryColumns

IMAPITable::QueryRows

This flag also controls the property types in the sort order returned by the IMAPITable::QuerySortOrder method.

See Also

IMsgServiceAdmin::ConfigureMsgService, IMsgServiceAdmin::DeleteMsgService


IMsgServiceAdmin::GetProviderTable

The IMsgServiceAdmin::GetProviderTable method provides access to the provider table — a listing of the service providers in the profile.

Quick Info

See IMsgServiceAdmin : IUnknown.

HRESULT GetProviderTable(
  ULONG ulFlags,
  LPMAPITABLE FAR * lppTable
);

Parameters

ulFlags
[in] Bitmask of flags that controls the type of the string columns returned in the table. The following flag can be set:
MAPI_UNICODE
The string columns are in Unicode format. If the MAPI_UNICODE flag is not set, the string columns are in ANSI format.
lppTable
[out] Pointer to a pointer to the provider table.

Return Value

S_OK
The provider table was successfully returned.

Remarks

The IMsgServiceAdmin::GetProviderTable method provides access to the MAPI provider table, a table that lists all of the address book, message store, transport, and message hook providers currently installed in the profile.

Unlike the provider table returned through IProviderAdmin::GetProviderTable, the provider table returned through IMsgServiceAdmin::GetProviderTable cannot include additional rows that represent information associated with one or more service providers in the profile.

Providers that have been deleted, or are in use but have been marked for deletion, are not included in the provider table. Provider tables are static, meaning that subsequent additions to or deletions from the profile are not reflected in the table.

If the profile has no providers, GetProviderTable returns a table with zero rows and the S_OK return value.

Setting the MAPI_UNICODE flag in the ulFlags parameter affects the format of the columns returned from the following IMAPITable methods:

IMAPITable::QueryColumns

IMAPITable::QueryRows

This flag also controls the property types in the sort order returned by the IMAPITable::QuerySortOrder method.

For a complete list of the columns in the provider table, see Provider Table.

Notes to Callers

To retrieve the rows of a provider table in transport order
  1. Call IMAPITable::Restrict to impose a property restriction that matches the PR_RESOURCE_TYPE property with MAPI_TRANSPORT_PROVIDER.
  2. Call IMAPITable::SortTable to sort the table by the PR_PROVIDER_ORDINAL column.
  3. Call IMAPITable::QueryRows to get the rows of the table.

An alternative to these calls is to make a single call to the HrQueryAllRows function with all of the appropriate data structures passed in.

If you retrieve the PR_SERVICE_UID columns in each of the rows, you can use this array of MAPIUID structures to set the transport order in a call to IMsgServiceAdmin::MsgServiceTransportOrder.

Setting the MAPI_UNICODE flag in the ulFlags parameter does the following:

  • Sets the string type to Unicode for data returned for the initial active columns of the provider table by the IMAPITable::QueryColumns method. The initial active columns for a provider table are those columns the QueryColumns method returns before the provider that contains the table calls the IMAPITable::SetColumns method.
  • Sets the string type to Unicode for data returned for the initial active rows of the provider table by QueryRows. The initial active rows for a provider table are those rows QueryRows returns before the provider that contains the table calls SetColumns.
  • Controls the property types of the sort order returned by the IMAPITable::QuerySortOrder method before the client that contains the provider table calls the IMAPITable::SortTable method.

See Also

IMsgServiceAdmin::GetMsgServiceTable, IMsgServiceAdmin::MsgServiceTransportOrder, IProviderAdmin::GetProviderTable


IMsgServiceAdmin::MsgServiceTransportOrder

The IMsgServiceAdmin::MsgServiceTransportOrder method sets the order in which transport providers are called to deliver a message.

Quick Info

See IMsgServiceAdmin : IUnknown.

HRESULT MsgServiceTransportOrder(
  ULONG cUID,
  LPMAPIUID lpUIDList,
  ULONG ulFlags
);

Parameters

cUID
[in] Count of unique identifiers in the lpUIDList parameter.
lpUIDList
[in] Pointer to an array of unique identifiers representing transport providers. The array contains one identifier for each transport provider configured in the current profile.
ulFlags
Reserved; must be zero.

Return Values

S_OK
The transport order was set successfully.
MAPI_E_BUSY
The value in the cUID parameter differs from the number of transport providers actually in the profile.
MAPI_E_NOT_FOUND
One or more of the MAPIUIDs passed in the lpUIDList parameter does not refer to a transport provider currently in the profile.

Remarks

The IMsgServiceAdmin::MsgServiceTransportOrder method sets the delivery order of transport providers within a profile. The lpUIDList parameter must contain a sorted list of transport-provider entry identifiers obtained from the PR_PROVIDER_UID property of the table returned from the IMsgServiceAdmin::GetProviderTable method. A client application must pass the complete list in lpUIDList.

SetTransportOrder overrides transport provider preferences such as the STATUS_XP_PREFER_LAST flag set in the PR_RESOURCE_FLAGS property.

See Also

MAPIUID


IMsgServiceAdmin::OpenProfileSection

The IMsgServiceAdmin::OpenProfileSection method opens a section of the current profile and returns an IProfSect pointer for further access.

Quick Info

See IMsgServiceAdmin : IUnknown.

HRESULT OpenProfileSection(
  LPMAPIUID lpUID,
  LPCIID lpInterface,
  ULONG ulFlags,
  LPPROFSECT FAR * lppProfSect
);

Parameters

ulFlags
[in] Bitmask of flags that controls access to the profile section. The following flags can be set:
lpUID
Pointer to the MAPIUID structure identifying the profile section.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the profile section. Passing NULL results in a pointer to its standard interface being returned in the lppProfSect parameter. The standard interface for a profile section is IProfSect.
ulFlags
[in] Bitmask of flags that controls access to the profile section. The following flags can be set:
MAPI_DEFERRED_ERRORS
Allows OpenProfileSection to return successfully, possibly before the profile section is fully accessible to the calling client. If the profile section is not accessible, making a subsequent call to it can result in an error.
MAPI_MODIFY
Requests read/write access. By default, profile sections are opened with read-only access, and clients should not work on the assumption that read/write access has been granted.
lppProfSect
[out] Pointer to a pointer to the profile section.

Return Values

S_OK
The profile section was successfully opened.
MAPI_E_NO_ACCESS
An attempt was made to access a profile section for which the caller has insufficient permissions.
MAPI_E_NOT_FOUND
The requested profile section does not exist.

Remarks

The IMsgServiceAdmin::OpenProfileSection method opens a profile section — an object that supports the IProfSect interface. Profile sections are used for reading information from and writing information to the session profile.

OpenProfileSection cannot be used to open profile sections owned by individual service providers.

Notes to Callers

Multiple clients can open a profile section with read-only access, but only one client can open a profile section with read/write access. If another client has a profile section open that you attempt to open by calling OpenProfileSection with the MAPI_MODIFY flag set, the call will fail, returning MAPI_E_NO_ACCESS.

A read-only open operation fails if the section is open for writing.

You can create a profile section by calling OpenProfileSection with the MAPI_MODIFY flag and a nonexistent MAPIUID structure in the lpUID parameter. Make sure you specify MAPI_MODIFY. If you set lpUID to point to a nonexistent MAPIUID and OpenProfileSection is set to use the default access mode of read-only, the call fails with MAPI_E_NOT_FOUND.

See Also

IMAPIProp : IUnknown, IMAPISession::OpenProfileSection, IProfSect : IMAPIProp, MAPIUID


IMsgServiceAdmin::RenameMsgService

The IMsgServiceAdmin::RenameMsgService method assigns a new name to a message service. This method is not currently supported.

Quick Info

See IMsgServiceAdmin : IUnknown.

HRESULT RenameMsgService(
  LPMAPIUID lpUID,
  ULONG ulFlags,
  LPTSTR lpszDisplayName
);

Parameters

lpUID
[in] Pointer to the MAPIUID structure holding the unique identifier for the message service to rename.
ulFlags
Reserved; must be zero.
lpszDisplayName
[in] Pointer to the new name for the message service.

Return Values

MAPI_E_NO_SUPPORT
MAPI does not support renaming this message service. RenameMsgService always returns this value.

Remarks

Clients wanting to assign a new name to a message service should assign a new name to its PR_SERVICE_NAME property. The names of service providers in a message service are stored in their PR_DISPLAY_NAME properties.

See Also

MAPIUID


IMsgServiceAdmin::SetPrimaryIdentity

The IMsgServiceAdmin::SetPrimaryIdentity method designates a message service to be the supplier of the primary identity for the profile.

Quick Info

See IMsgServiceAdmin : IUnknown.

HRESULT SetPrimaryIdentity(
  LPMAPIUID lpUID,
  ULONG ulFlags
);

Parameters

lpUID
[in] Pointer to the MAPIUID structure holding the unique identifier for the message service to supply the primary identity, or NULL, indicating that SetPrimaryIdentity should clear the current identity.
ulFlags
Reserved; must be zero.

Return Values

S_OK
The message service was successfully assigned the supplier of the primary identity.
MAPI_E_NO_ACCESS
SetPrimaryIdentity attempted to designate a message service that has the SERVICE_NO_PRIMARY_IDENTITY flag set in its PR_RESOURCE_FLAGS property.

Remarks

The IMsgServiceAdmin::SetPrimaryIdentity method establishes a message service as the supplier of the primary identity for the profile. The primary identity is typically the user logged on to the message service. It is represented by three properties:

PR_IDENTITY_DISPLAY

PR_IDENTITY_ENTRYID

PR_IDENTITY_SEARCH_KEY

Every service provider in the designated message service sets these three properties to the display name, entry identifier, and search key of the messaging user that is supplying the primary identity. Clients can retrieve the primary identity's entry identifier by calling IMAPISession::QueryIdentity.

Another property, PR_RESOURCE_FLAGS, is set to STATUS_PRIMARY_IDENTITY for every provider that is a member of the message service supplying the primary identity and to SERVICE_PRIMARY_IDENTITY for the message service. When a service provider cannot supply the primary identity for its message service, it sets PR_RESOURCE_FLAGS to STATUS_NO_PRIMARY_IDENTITY. SetPrimaryIdentity sets the PR_RESOURCE_FLAGS property of each message service that is not supplying the primary identity to SERVICE_NO_PRIMARY_IDENTITY.

Each message service provider that MAPI has information about can establish an identity for each of its users when a client logs on to the service. However, because MAPI supports connections to multiple service providers for each MAPI session, there is no firm definition of a particular user's identity for the MAPI session as a whole; a user's identity depends on which service is involved. Clients can call SetPrimaryIdentity to designate one of the many identities established for a user by message services as the primary identity for that user.

See Also

IMAPISession::QueryIdentity, MAPIUID


IMsgStore : IMAPIProp

The IMsgStore interface provides access to message store information and to messages and folders.

Quick Info

Header file: | MAPIDEFS.H
Exposed by: | Message store object
Implemented by: | Message store providers
Called by: | Client applications, the MAPI spooler, MAPI
Interface identifier: | IID_IMsgStore
Pointer type: | LPMDB
Transaction model: | Nontransacted

Vtable Order

Advise | Registers to receive notification of specified events affecting the message store.
Unadvise | Cancels the sending of notifications previously set up with a call to the IMsgStore::Advise method.
CompareEntryIDs | Compares two entry identifiers to determine if they refer to the same entry within a message store.
OpenEntry | Opens a folder or message and returns an interface pointer for further access.
SetReceiveFolder | Establishes a folder as the destination for incoming messages of a particular message class.
GetReceiveFolder | Obtains the folder that was established as the destination for incoming messages of a specified message class or the default receive folder for the message store.
GetReceiveFolderTable | Provides access to the receive folder table — a table with information about all of the receive folders for the message store.
StoreLogoff | Enables the orderly logoff of the message store.
AbortSubmit | Attempts to remove a message from the outgoing queue.
GetOutgoingQueue | Provides access to the outgoing queue table — a table with information about all of the messages in the message store's outgoing queue. This method is called only by the MAPI spooler.
SetLockState | Locks or unlocks a message. This method is called only by the MAPI spooler.
FinishedMsg | Enables the message store provider to perform processing on a sent message. This method is called only by the MAPI spooler.
NotifyNewMail | Informs the message store that a new message has arrived. This method is called only by the MAPI spooler.
Required properties |  | Access level
PR_DISPLAY_NAME |  | Read/write
PR_ENTRYID |  | Read-only
PR_OBJECT_TYPE |  | Read-only
PR_RECORD_KEY |  | Read-only
PR_STORE_ENTRYID |  | Read-only
PR_STORE_RECORD_KEY |  | Read-only
PR_MDB_PROVIDER |  | Read-only
PR_STORE_SUPPORT_MASK |  | Read-only

Properties for IPM message stores |
PR_IPM_OUTBOX_ENTRYID | PR_IPM_OUTBOX_SEARCH_KEY
PR_IPM_SENTMAIL_ENTRYID | PR_IPM_SENTMAIL_SEARCH_KEY
PR_IPM_SUBTREE_ENTRYID | PR_IPM_SUBTREE_SEARCH_KEY
PR_IPM_WASTEBASKET_ENTRYID | PR_IPM_WASTEBASKET_SEARCH_KEY
PR_MDB_PROVIDER | PR_STORE_SUPPORT_MASK


IMsgStore::AbortSubmit

The IMsgStore::AbortSubmit method attempts to remove a message from the outgoing queue.

Quick Info

See IMsgStore : IMAPIProp.

AbortSubmit(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  ULONG ulFlags
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the message to remove from the outgoing queue.
ulFlags
Reserved; must be zero.

Return Values

S_OK
The message was successfully removed from the outgoing queue.
MAPI_E_NOT_IN_QUEUE
The message identified by lpEntryID is no longer in the message store's outgoing queue, typically because it has already been sent.
MAPI_E_UNABLE_TO_ABORT
The message identified by lpEntryID is locked by the MAPI spooler, and the operation cannot be aborted.

Remarks

The IMsgStore::AbortSubmit method attempts to remove a submitted message from the message store's outgoing queue.

Notes to Callers

After a message is submitted, aborting the submission by calling AbortSubmit is the only action that can be performed on the message. Do not expect AbortSubmit always to succeed. Depending on how the underlying messaging system is implemented, it might not be possible to cancel the sending of the message.

See Also

IMessage::SubmitMessage


IMsgStore::Advise

The IMsgStore::Advise method registers to receive notification of specified events affecting the message store.

Quick Info

See IMsgStore : IMAPIProp.

HRESULT Advise(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  ULONG ulEventMask,
  LPMAPIADVISESINK lpAdviseSink,
  ULONG FAR * lpulConnection
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the folder or message about which notifications should be generated, or NULL. If lpEntryID is set to NULL, Advise registers for notifications on the entire message store.
ulEventMask
[in] A mask of values indicating the types of notification events that the caller is interested in and should be included in the registration. There is a corresponding NOTIFICATION structure associated with each type of event that holds information about the event.

The following are valid values for the ulEventMask parameter:

fnevCriticalError
Registers for notifications about severe errors, such as insufficient memory.
fnevExtended
Registers for notifications about events specific to the particular message store provider.
fnevNewMail
Registers for notifications about the arrival of new messages.
fnevObjectCreated
Registers for notifications about the creation of a new folder or message.
fnevObjectCopied
Registers for notifications about a folder or message being copied.
fnevObjectDeleted
Registers for notifications about a folder or message being deleted.
fnevObjectModified
Registers for notifications about a folder or message being modified.
fnevObjectMoved
Registers for notifications about a folder or message being moved.
fnevSearchComplete
Registers for notifications about the completion of a search operation.
lpAdviseSink
[in] Pointer to an advise sink object to receive the subsequent notifications. This advise sink object must have already been allocated.
lpulConnection
[out] Pointer to a nonzero number that represents the connection between the caller's advise sink object and the session.
lpAdviseSink
[in] Pointer to an advise sink object to receive the subsequent notifications. This advise sink object must have already been allocated.
lpulConnection
[out] Pointer to a nonzero connection number representing the connection between the caller's advise sink object and the message store.

Return Value

S_OK
The registration was successful.
MAPI_E_NO_SUPPORT
The message store provider does not support registration for notification through the message store.

Remarks

The IMsgStore::Advise method establishes a connection between the caller's advise sink object and either the message store or an object in the message store. This connection is used to send notifications to the advise sink when one or more events as specified in the ulEventMask parameter occur to the advise source object. When lpEntryID points to a valid entry identifier, the advise source is the object identified by this entry identifier. When lpEntryID is NULL, the advise source is the message store.

To send a notification, either the message store provider or MAPI calls the registered advise sink's IMAPIAdviseSink::OnNotify method. One of the parameters to OnNotify, a notification structure, contains information that describes the specific event.

Notes to Implementers

You can support notification with or without help from MAPI. MAPI has three support object methods for helping service providers implement notification: IMAPISupport::Subscribe, IMAPISupport::Unsubscribe, and IMAPISupport::Notify. If you elect to use the MAPI support methods, call Subscribe when your Advise method is called and release the lpAdviseSink pointer.

If you elect to support notification yourself, call the IUnknown::AddRef method of the advise sink represented by the lpAdviseSink parameter to keep a copy of this pointer. Maintain this copy until your IMsgStore::Unadvise method is called to cancel the registration.

Regardless of how you support notification, assign a nonzero connection number to the notification registration and return it in the lpulConnection parameter. Do not release this connection number until Unadvise has been called and has completed.

Notes to Callers

On systems that support multiple threads of execution, the call to OnNotify can also occur on any thread at any time. If you must be assured that notifications only occur at a particular time on a particular thread, call HrThisThreadAdviseSink to generate the advise sink object that you pass to Advise.

After a call to Advise has succeeded and before Unadvise has been called to cancel the registration, be prepared for the advise sink object to be released. It is wise to release your advise sink object after Advise returns unless you have a specific long-term use for it.

For an overview of the notification process, see Event Notification in MAPI.

For more information on handling notifications, see Handling Notifications.

See Also

HrThisThreadAdviseSink, IMAPIAdviseSink::OnNotify, IMsgStore::Unadvise, NOTIFICATION


IMsgStore::CompareEntryIDs

The IMsgStore::CompareEntryIDs method compares two entry identifiers to determine if they refer to the same entry within a message store. MAPI only passes this call to a service provider if the unique identifiers (UIDs) in both entry identifiers to be compared are handled by that provider.

Quick Info

See IMsgStore : IMAPIProp.

HRESULT CompareEntryIDs(
  ULONG cbEntryID1,
  LPENTRYID lpEntryID1,
  ULONG cbEntryID2,
  LPENTRYID lpEntryID2,
  ULONG ulFlags,
  ULONG FAR * lpulResult
);

Parameters

cbEntryID1
[in] Count of bytes in the entry identifier pointed to by the lpEntryID1 parameter.
lpEntryID1
[in] Pointer to the first entry identifier to be compared.
cbEntryID2
[in] Count of bytes in the entry identifier pointed to by the lpEntryID2 parameter.
lpEntryID2
[in] Pointer to the second entry identifier to be compared.
ulFlags
Reserved; must be zero.
lpulResult
[out] Pointer to the result of the comparison, set toTRUE if the two entry identifiers refer to the same object and FALSE otherwise.

Return Values

S_OK
The comparison was successful.
MAPI_E_UNKNOWN_ENTRYID
One or both of the entry identifiers specified as parameters do not refer to objects, possibly because the corresponding objects are unopened and inaccessible at present.

Remarks

The IMsgStore::CompareEntryIDs method compares two entry identifiers belonging to the message store to determine whether they refer to the same object.

Notes to Callers

CompareEntryIDs is useful because an object can have more than one valid entry identifier; such a situation can occur, for example, after a new version of a message store provider is installed.

If CompareEntryIDs returns an error, do not take any action based on the result of the comparison. Instead, take the most conservative approach possible. CompareEntryIDs might fail if, for example, one or both of the entry identifiers contains an invalid MAPIUID.

See Also

MAPIUID


IMsgStore::FinishedMsg

The IMsgStore::FinishedMsg method enables the message store provider to perform processing on a sent message. This method is called only by the MAPI spooler.

Quick Info

See IMsgStore : IMAPIProp.

HRESULT FinishedMsg(
  ULONG ulFlags,
  ULONG cbEntryID,
  LPENTRYID lpEntryID
);

Parameters

ulFlags
Reserved; must be zero.
cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the message to be processed.

Return Values

S_OK
Processing on the sent message was successful.
MAPI_E_NO_SUPPORT
The message store provider does not support sent message processing. This error value is returned if the caller is not the MAPI spooler.

Remarks

The IMsgStore::FinishedMsg method performs processing on a sent message. This processing can involve deleting the message, moving it to a different folder, or both actions. The type of processing depends on whether or not the PR_DELETE_AFTER_SUBMIT and PR_SENTMAIL_ENTRYID properties are set.

Notes to Implementers

In your implementation of FinishedMsg, unlock the message identified by lpEntryID and perform the appropriate processing. The target message will always be locked; the MAPI spooler never passes the entry identifier for an unlocked message to FinishedMsg.

It is possible that neither of these properties are set, both are set, or one or the other is set. The following table describes the action you should take based on the settings:

If neither property is set: | Leave the message in the folder from which it was sent (typically the Outbox).
If both properties are set: | Move the message to the indicated folder, if desired, and then delete it.
If PR_SENTMAIL_ENTRYID is set: | Move the message to the indicated folder.
If PR_DELETE_AFTER_SUBMIT is set: | Delete the message.

After you have taken whatever action is appropriate, call IMAPISupport::DoSentMail.

See Also

IMAPISupport::DoSentMail


IMsgStore::GetOutgoingQueue

The IMsgStore::GetOutgoingQueue method provides access to the outgoing queue table — a table with information about all of the messages in the message store's outgoing queue. This method is called only by the MAPI spooler.

Quick Info

See IMsgStore : IMAPIProp.

HRESULT GetOutgoingQueue(
  ULONG ulFlags,
  LPMAPITABLE FAR * lppTable
);

Parameters

ulFlags
Reserved; must be zero.
lppTable
[out] Pointer to a pointer to the outgoing queue table.

Return Value

S_OK
The outgoing queue table was successfully returned.

Remarks

The IMsgStore::GetOutgoingQueue method provides the MAPI spooler with access to the table showing the message store's queue of outgoing messages. Typically, messages are placed in the outgoing queue table after their IMessage::SubmitMessage method is called. However, because the order of submission affects the order of preprocessing and submission to the transport provider, some messages that have been marked for sending might not appear in the outgoing queue table immediately.

Notes to Implementers

For a list of the properties that must be included as columns in your outgoing queue table, see Outgoing Queue Tables.

Because the MAPI spooler is designed to accept messages from a message store in ascending order of submission time, either allow the MAPI spooler to sort the outgoing queue table to match this order or establish it as the default sort order.

You must support notifications for the outgoing message queue table, ensuring that the MAPI spooler is notified when the contents of the queue change.

See Also

IMessage::SubmitMessage


IMsgStore::GetReceiveFolder

The IMsgStore::GetReceiveFolder method obtains the folder that was established as the destination for incoming messages of a specified message class or the default receive folder for the message store.

Quick Info

See IMsgStore : IMAPIProp.

HRESULT GetReceiveFolder(
  LPTSTR lpszMessageClass,
  ULONG ulFlags,
  ULONG FAR * lpcbEntryID,
  LPENTRYID FAR * lppEntryID,
  LPTSTR FAR * lppszExplicitClass
);

Parameters

lpszMessageClass
[in] Pointer to a message class that is associated with a receive folder. If the lpszMessageClass parameter is set to NULL or an empty string, GetReceiveFolder returns the default receive folder for the message store.
ulFlags
[in] Bitmask of flags that controls the type of the passed-in and returned strings. The following flag can be set:
MAPI_UNICODE
The message class string is in Unicode format. If the MAPI_UNICODE flag is not set, the message class string is in ANSI format.
lpcbEntryID
[out] Pointer to the count of bytes in the entry identifier pointed to by the lppEntryID parameter.
lppEntryID
[out] Pointer to a pointer to the entry identifier for the requested receive folder.
lppszExplicitClass
[out] Pointer to a pointer to the message class that explicitly sets as its receive folder the folder pointed to by lppEntryID. This message class should either be the same as the class in the lpszMessageClass parameter or of a superclass of that class. Passing NULL indicates that the folder pointed to by lppEntryID is the default receive folder for the message store.

Return Value

S_OK
The receive folder was successfully returned.

Remarks

The IMsgStore::GetReceiveFolder method obtains the entry identifier of a receive folder, a folder designated to receive incoming messages of a particular message class. Callers can specify a message class or NULL in the lpszMessageClass parameter. If lpszMessageClass is NULL, GetReceiveFolder returns:

  • In lppszExplicitClass, the name of the first superclass of the message class pointed to by lpszMessageClass that does explicitly set a receive folder.
  • In lppEntryID, the entry identifier of the receive folder for the superclass pointed to by the lppszExplicitClass parameter.

For example, suppose the receive folder of the message class IPM.Note has been set to the entry identifier of the Inbox and GetReceiveFolder is called with the contents of lpszMessageClass set to IPM.Note.Phone. If IPM.Note.Phone does not have an explicit receive folder set, GetReceiveFolder returns the entry identifier of the Inbox in lppEntryID and IPM.Note in lppszExplicitClass.

If the client calls GetReceiveFolder for a message class and has not set a receive folder for that message class, lppszExplicitClass is either a zero-length string, a string in Unicode format, or a string in ANSI format depending on whether the client set the MAPI_UNICODE flag in the ulFlags parameter.

A default receive folder, obtained by passing NULL in the lpszMessageClass parameter, always exists for every message store.

A client should call the MAPIFreeBuffer function when it is done with the entry identifier returned in lppEntryID to free the memory that holds that entry identifier. It should also call MAPIFreeBuffer when it is done with the message class string returned in lppszExplicitClass to free the memory that holds that string.

See Also

MAPIFreeBuffer


IMsgStore::GetReceiveFolderTable

The IMsgStore::GetReceiveFolderTable method provides access to the receive folder table, a table that includes information about all of the receive folders for the message store.

Quick Info

See IMsgStore : IMAPIProp.

HRESULT GetReceiveFolderTable(
  ULONG ulFlags,
  LPMAPITABLE FAR * lppTable
);

Parameters

ulFlags
[in] Bitmask of flags that controls table access. The following flags can be set:
MAPI_DEFERRED_ERRORS
Allows GetReceiveFolderTable to return successfully, possibly before the table is fully accessible to the caller. If the table is not fully accessible, making a subsequent table call can result in an error.
MAPI_UNICODE
The returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppTable
[out] Pointer to a pointer to the receive folder table.

Return Value

S_OK
The receive folder table was successfully returned.

Remarks

The IMsgStore::GetReceiveFolderTable method provides access to a table showing the property settings for all of the message store's receive folders.

Notes to Implementers

For a list of required columns in a receive folder table, see Receive Folder Tables.

Implement your receive folder tables to support setting property restrictions on the PR_RECORD_KEY property, allowing easy access to particular receive folders.

Notes to Callers

Setting the MAPI_UNICODE flag in the ulFlags parameter affects the format of the columns returned from the following IMAPITable methods:

IMAPITable::QueryColumns

IMAPITable::QueryRows

This flag also controls the property types in the sort order returned by the IMAPITable::QuerySortOrder method.

See Also

IMAPITable::QueryColumns, IMAPITable::QueryRows, IMAPITable::QuerySortOrder, IMAPITable::SetColumns


IMsgStore::NotifyNewMail

The IMsgStore::NotifyNewMail method informs the message store that a new message has arrived. This method is called only by the MAPI spooler.

Quick Info

See IMsgStore : IMAPIProp.

HRESULT NotifyNewMail(
  LPNOTIFICATION lpNotification
);

Parameters

lpNotification
[in] Pointer to a NOTIFICATION structure describing the new message notification.

Return Value

S_OK
The message store was successfully notified.

Remarks

The IMsgStore::NotifyNewMail method is called by the MAPI spooler to inform the message store that a message is ready for delivery.

Notes to Implementers

When NotifyNewMail is called, send a new mail notification to all registered clients. This can be done by calling IMAPISupport::Notify if you elect to use the support object methods or with your own implementation. A registered client is one that has called IMsgStore::Advise and set the lpEntryID parameter to NULL and the ulEventMask parameter to fnevNewMail.

Do not modify or free the memory for the NOTIFICATION structure that describes the new mail notification. Copy the NOTIFICATION structure by calling the utility function ScCopyNotifications to make use of the information in its members.

See Also

IMAPISupport::Subscribe, IMAPISupport::Unsubscribe, NOTIFICATION, ScCopyNotifications


IMsgStore::OpenEntry

The IMsgStore::OpenEntry method opens a folder or message and returns an interface pointer for further access.

Quick Info

See IMsgStore : IMAPIProp.

HRESULT OpenEntry(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  LPCIID lpInterface,
  ULONG ulFlags,
  ULONG FAR * lpulObjType,
  LPUNKNOWN FAR * lppUnk
);

Parameters

cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the object to open, or NULL. If lpEntryID is set to NULL, OpenEntry opens the root folder for the message store.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the opened object. Passing NULL results in the object's standard interface being returned which is IMAPIFolder for folders and IMessage for messages.
ulFlags
[in] Bitmask of flags that controls how the object is opened. The following flags can be used:
MAPI_BEST_ACCESS
Requests that the object be opened with the maximum network permissions allowed for the user and the maximum client application access. For example, if the client has read/write access, the object should be opened with read/write access; if the client has read-only access, the object should be opened with read-only access.
MAPI_DEFERRED_ERRORS
Allows OpenEntry to return successfully, possibly before the object is fully accessible to the calling client. If the object is not accessible, making a subsequent object call can result in an error.
MAPI_MODIFY
Requests read/write access. By default, objects are opened with read-only access, and clients should not work on the assumption that read/write access has been granted.
lpulObjType
[out] Pointer to the type of the opened object.
lppUnk
[out] Pointer to a pointer to the opened object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_NO_ACCESS
An attempt was made to modify a read-only object or to access an object for which the user has insufficient permissions.

Remarks

The IMsgStore::OpenEntry method opens a folder or message and returns a pointer to an interface that can be used for further access.

Notes to Callers

Folders and messages are automatically opened with read-only access, unless you set the MAPI_MODIFY or MAPI_BEST_ACCESS flag in the ulFlags parameter. Setting one of these flags does not guarantee a particular type of access; the permissions that you are granted depends on the message store provider, your access level, and the object. To determine the access level of the opened object, retrieve its PR_ACCESS_LEVEL property.

Although IMsgStore::OpenEntry can be used to open any folder or message, it is usually faster to use IMAPIContainer::OpenEntry if you have access to the folder containing the folder or message to be opened.

Check the value returned in the lpulObjType parameter to determine that the object type returned is what you expected. If the object type is not the expected type, cast the pointer from the lppUnk parameter to a pointer of the appropriate type. For example, if you are opening a folder, cast lppUnk to a pointer of type LPMAPIFOLDER.

See Also

IMAPIContainer::OpenEntry


IMsgStore::SetLockState

The IMsgStore::SetLockState method locks or unlocks a message. This method is called only by the MAPI spooler.

Quick Info

See IMsgStore : IMAPIProp.

HRESULT SetLockState(
  LPMESSAGE lpMessage,
  ULONG ulLockState
);

Parameters

lpMessage
[in] Pointer to the message to lock or unlock.
ulLockState
[in] Value indicating whether the message should be locked or unlocked. One of the following values are valid:
MSG_LOCKED
The message should be locked.
MSG_UNLOCKED
The message should be unlocked.

Return Value

S_OK
The lock state of the message was successfully set.

Remarks

The IMsgStore::SetLockState method locks or unlocks a message. SetLockState can only be called by the MAPI spooler while it is sending the message.

Usually, when the MAPI spooler calls SetLockState to lock a message, it only locks the oldest message — that is, the next message queued for the MAPI spooler to send. If the oldest message in the queue is waiting for a temporarily unavailable transport provider, and the next message in the queue uses a different transport provider, the MAPI spooler can begin processing the later message. It begins processing by locking that message using SetLockState.

Notes to Implementers

After the MAPI spooler has called SetLockState with the ulLockState parameter set to MSG_LOCKED, calls to IMsgStore::AbortSubmit to cancel the message's transmission must fail.

Call the message's IMAPIProp::SaveChanges method in your SetLockState implementation so that any changes made to the message before the SetLockState call was received are saved.

See Also

IMsgStore::AbortSubmit, IMsgStore::FinishedMsg


IMsgStore::SetReceiveFolder

The IMsgStore::SetReceiveFolder method establishes a folder as the destination for incoming messages of a particular message class.

Quick Info

See IMsgStore : IMAPIProp.

HRESULT SetReceiveFolder(
  LPTSTR lpszMessageClass,
  ULONG ulFlags,
  ULONG cbEntryID,
  LPENTRYID lpEntryID
);

Parameters

lpszMessageClass
[in] Pointer to the message class that is to be associated with the new receive folder. If the lpszMessageClass parameter is set to NULL or an empty string, SetReceiveFolder sets the default receive folder for the message store.
ulFlags
[in] Bitmask of flags that controls the type of the text in the passed-in strings. The following flag can be set:
MAPI_UNICODE
The message class string is in Unicode format. If the MAPI_UNICODE flag is not set, the message class string is in ANSI format.
cbEntryID
[in] Count of bytes in the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the folder to establish as the receive folder. If the lpEntryID parameter is set to NULL, SetReceiveFolder replaces the current receive folder with the message store's default.

Return Value

S_OK
A receive folder was successfully established.

Remarks

The IMsgStore::SetReceiveFolder method sets or changes the receive folder for a particular message class. With SetReceiveFolder, a client can, by using successive calls, specify a different receive folder for each message class defined or specify that incoming messages for multiple message classes all go to the same folder. A client can, for example, have its own class of messages arrive in its own folder. For instance, a fax application can designate a folder where the store provider places incoming faxes and one where the provider places outgoing faxes.

If an error occurs while calling SetReceiveFolder, the receive folder setting remains unchanged.

If SetReceiveFolder changes the receive folder setting with lpEntryID set to NULL, indicating the default receive folder should be set, SetReceiveFolder returns S_OK even if there was no existing setting for the indicated message class.


IMsgStore::StoreLogoff

The IMsgStore::StoreLogoff method enables the orderly logoff of the message store.

Quick Info

See IMsgStore : IMAPIProp.

HRESULT StoreLogoff(
  ULONG FAR * lpulFlags
);

Parameters

lpulFlags
[in, out] Bitmask of flags that controls logoff from the message store. On input, all flags set for this parameter are mutually exclusive; a caller must specify only one flag per call. The following flags are valid on input:
LOGOFF_ABORT
Any transport provider activity for this message store should be stopped before logoff. Control is returned to the caller after activity is stopped. If any transport provider activity is taking place, the logoff does not occur and no change in the behavior of the MAPI spooler or transport providers occurs. If transport provider activity is quiet, the MAPI spooler releases the store.
LOGOFF_NO_WAIT
The message store should not wait for messages from transport providers before closing. Outbound messages that are ready to be sent are sent. If this store contains the default Inbox, any in-process messages are received, and then further reception is disabled. When all activity is completed, the MAPI spooler releases the store, and control is returned to the caller immediately.
LOGOFF_ORDERLY
The message store should not wait for information from transport providers before closing. Messages currently being processed are completed, but no new messages are processed. When all activity is completed, the MAPI spooler releases the store, and control is returned to the store provider immediately.
LOGOFF_PURGE
The logoff should work the same as if the LOGOFF_NO_WAIT flag is set, but that either IXPLogon::FlushQueues or IMAPIStatus::FlushQueues for the appropriate transport providers should be called. The LOGOFF_PURGE flag returns control to the caller after completion.
LOGOFF_QUIET
If any transport provider activity is taking place, the logoff should not occur.

The following flags are valid on output:

LOGOFF_INBOUND
Inbound messages are currently arriving.
LOGOFF_OUTBOUND
Outbound messages are in the process of being sent.
LOGOFF_OUTBOUND_QUEUE
Outbound messages are pending, that is, they are in the Outbox.

Return Value

S_OK
The logoff completed successfully.

Remarks

The IMsgStore::StoreLogoff method exerts control over the interaction of the message store and transport providers during the logoff process. Calling StoreLogoff is valid only for message stores that are being used by only the caller. When two clients, for example, are using the same message store and one of them calls StoreLogoff, the message store is immediately released and control is returned to the calling client.

Notes to Implementers

Save the flags that are passed to StoreLogoff and pass them when you call IMAPISupport::StoreLogoffTransports. Do not call StoreLogoffTransports until the message store's reference count drops to zero. Multiple calls to StoreLogoffTransports simply overwrite the saved flags.

If no call has been made to StoreLogoff before the message store's reference count reaches zero, set the LOGOFF_ABORT flag in the ulFlags parameter that you pass to StoreLogoffTransports.

See Also

IMAPIStatus::FlushQueues, IMAPISupport::StoreLogoffTransports, IXPLogon::FlushQueues


IMsgStore::Unadvise

The IMsgStore::Unadvise method cancels the sending of notifications previously set up with a call to the IMsgStore::Advise method.

Quick Info

See IMsgStore : IMAPIProp.

HRESULT Unadvise(
  ULONG ulConnection
);

Parameters

ulConnection
[in] Connection number associated with an active notification registration. The value of ulConnection must have been returned by a previous call to IMsgStore::Advise.

Return Value

S_OK
The registration was successfully canceled.

Remarks

The IMsgStore::Unadvise method cancels a registration for notification. Unadvise releases its pointer to the caller's advise sink, which it received in the Advise call used for registration.

Generally, Unadvise calls the advise sink's IUnknown::Release method during the Unadvise call, but if another thread is in the process of calling the advise sink's IMAPIAdviseSink::OnNotify method, the Release call is delayed until the OnNotify method returns.

See Also

IMAPIAdviseSink::OnNotify, IMsgStore::Advise


IMSLogon : IUnknown

The IMSLogon interface is used to access resources in a message store logon object.

Quick Info

Header file: | MAPISPI.H
Exposed by: | Message store logon objects
Implemented by: | Message store providers
Called by: | MAPI
Interface identifier: | IID_IMSLogon
Pointer type: | LPMSLOGON

Vtable Order

GetLastError | Returns a MAPIERROR structure containing information about the last error that occurred for the message store object.
Logoff | Logs off a message store provider.
OpenEntry | Opens a folder or message object and returns a pointer to the object to provide further access.
CompareEntryIDs | Compares two entry identifiers to determine if they refer to the same object.
Advise | Registers a message store provider for notifications about changes within the message store.
Unadvise | Removes an object's registration for notification of message store changes previously established with a call to the IMSLogon::Advise method.
OpenStatusEntry | Opens a status object.

Remarks

The message store logon object is the part of an open message store provider that is called directly by MAPI. There is a one-to-one correspondence between the message store logon object called by MAPI and the message store object called by client applications; you can think of the logon and store objects as one object exposing two interfaces. The two objects are created together and freed together.


IMSLogon::Advise

The IMSLogon::Advise method registers a object with a message store provider for notifications about changes within the message store. The message store will then send notifications about changes to the registered object.

Quick Info

See IMSLogon : IUnknown.

HRESULT Advise(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  ULONG ulEventMask,
  LPMAPIADVISESINK lpAdviseSink,
  ULONG FAR * lpulConnection
);

Parameters

cbEntryID
[in] Size, in bytes, of the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier of the object about which notifications should be generated. This object can be a folder, a message, or any other object in the message store. Alternatively, if MAPI sets the cbEntryID parameter to zero and passes NULL for lpEntryID, the advise sink provides notifications about changes to the entire message store.
ulEventMask
[in] Event mask of the types of notification events occurring for the object about which MAPI will generate notifications. The mask filters specific cases. Each event type has a structure associated with it that holds additional information about the event. The following table lists the possible event types along with their corresponding structures.
Notification event type Corresponding structure
fnevCriticalError
 ERROR_NOTIFICATION
fnevNewMail
 NEWMAIL_NOTIFICATION
fnevObjectCreated
 OBJECT_NOTIFICATION
fnevObjectDeleted
 OBJECT_NOTIFICATION
fnevObjectModified
 OBJECT_NOTIFICATION
fnevObjectCopied
 OBJECT_NOTIFICATION
fnevObjectMoved
 OBJECT_NOTIFICATION
fnevSearchComplete
 OBJECT_NOTIFICATION
fnevStatusObjectModified
 STATUS_OBJECT_NOTIFICATION

lpAdviseSink
[in] Pointer to an advise sink object to be called when an event occurs for the session object about which notification has been requested. This advise sink object must already exist.
lpulConnection
[out] Pointer to a variable that upon a successful return holds the connection number for the notification registration. The connection number must be nonzero.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_NO_SUPPORT
The operation is not supported by MAPI or by one or more service providers.

Remarks

Message store providers implement the IMSLogon::Advise method to register an object for notification callbacks. Whenever a change occurs to the indicated object, the provider checks to see what event mask bit was set in the ulEventMask parameter and thus what type of change occurred. If a bit is set, then the provider calls the IMAPIAdviseSink::OnNotify method for the advise sink object indicated by the lpAdviseSink parameter to report the event. Data passed in the notification structure to the OnNotify routine describes the event.

The call to OnNotify can occur during the call that changes the object, or at any following time. On systems that support multiple threads of execution, the call to OnNotify can occur on any thread. For a way to turn a call to OnNotify that might happen at an inopportune time into one that is safer to handle, a client application should use the HrThisThreadAdviseSink function.

To provide notifications, the message store provider implementing Advise needs to keep a copy of the pointer to the lpAdviseSink advise sink object; to do so, it calls the IUnknown::AddRef method for the advise sink to maintain its object pointer until notification registration is canceled with a call to the IMSLogon::Unadvise method. The Advise implementation should assign a connection number to the notification registration and call AddRef on this connection number before returning it in the lpulConnection parameter. Service providers can release the advise sink object before the registration is canceled, but they must not release the connection number until Unadvise has been called.

After a call to Advise has succeeded and before Unadvise has been called, providers must be prepared for the advise sink object to be released. A provider should therefore release its advise sink object after Advise returns unless it has a specific long-term use for it.

For more information about the notification process, see Event Notification in MAPI.

See Also

HrThisThreadAdviseSink, IMAPIAdviseSink::OnNotify, IMSLogon::Unadvise, NOTIFICATION


IMSLogon::CompareEntryIDs

The IMSLogon::CompareEntryIDs method compares two entry identifiers to determine if they refer to the same object. MAPI only refers this call to a service provider if the unique identifiers (UIDs) in both entry identifiers to be compared are handled by that provider.

Quick Info

See IMSLogon : IUnknown.

HRESULT CompareEntryIDs(
  ULONG cbEntryID1,
  LPENTRYID lpEntryID1,
  ULONG cbEntryID2,
  LPENTRYID lpEntryID2,
  ULONG ulFlags,
  ULONG FAR * lpulResult
);

Parameters

cbEntryID1
[in] Size, in bytes, of the entry identifier pointed to by the lpEntryID1 parameter.
lpEntryID1
[in] Pointer to the first entry identifier to be compared.
cbEntryID2
[in] Size, in bytes, of the entry identifier pointed to by the lpEntryID2 parameter.
lpEntryID2
[in] Pointer to the second entry identifier to be compared.
ulFlags
Reserved; must be zero.
lpulResult
[out] Pointer to the returned result of the comparison; this variable is TRUE if the two entry identifiers refer to the same object, and FALSE otherwise.

Return Value

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Message store providers implement the IMSLogon::CompareEntryIDs method to compare two entry identifiers for a given entry within a message store to determine whether they refer to the same object. If the two entry identifiers refer to the same object, then CompareEntryIDs sets the lpulResult parameter to TRUE; if they refer to different objects, CompareEntryIDs sets lpulResult to FALSE.

CompareEntryIDs is useful because an object can have more than one valid entry identifier; such a situation can occur, for example, after a new version of a message store provider is installed.


IMSLogon::GetLastError

The IMSLogon::GetLastError method returns a MAPIERROR structure containing information about the last error that occurred for the message store object.

Quick Info

See IMSLogon : IUnknown.

HRESULT GetLastError(
  HRESULT hResult,
  ULONG ulFlags,
  LPMAPIERROR FAR * lppMAPIError
);

Parameters

hResult
[in] HRESULT data type containing the error value generated in the previous method call for the message store object.
ulFlags
[in] Bitmask of flags that controls the type of the returned strings. The following flag can be set:
MAPI_UNICODE
The strings in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppMAPIError
[out] Pointer to a pointer to the returned MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Remarks

Use the IMSLogon::GetLastError method to retrieve information to display in a message to the user regarding the last error returned from a method call for the message store object.

To release all the memory allocated by MAPI for the returned MAPIERROR structure, client applications need only call the MAPIFreeBuffer function.

The return value from GetLastError must be S_OK for an application to make use of the MAPIERROR structure. Even if the return value is S_OK, a MAPIERROR structure might not be returned. If the implementation cannot determine what the last error was, or if a MAPIERROR structure is not available for that error, GetLastError returns a pointer to NULL in lppMAPIError instead.

See Also

MAPIERROR, MAPIFreeBuffer


IMSLogon::Logoff

The IMSLogon::Logoff method logs off a message store provider.

Quick Info

See IMSLogon : IUnknown.

HRESULT Logoff(
  ULONG FAR * lpulFlags
);

Parameters

lpulFlags
Reserved; must be a pointer to zero.

Return Value

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Message store providers implement the IMSLogon::Logoff method to forcibly shut down a message store provider. IMSLogon::Logoff is called:

  • While MAPI is logging off a client after a call to the IMAPISession::Logoff method.
  • While MAPI is logging off a message store provider. In this case, IMSLogon::Logoff is called as part of MAPI processing the IUnknown::Release method of the support object that the message store provider creates while it is processing an IMsgStore::StoreLogoff or IUnknown::Release method call on a message store object.

See Also

IMAPISession::Logoff, IMAPISupport : IUnknown, IMsgStore::StoreLogoff, IMSProvider::Logon, MAPIFreeBuffer


IMSLogon::OpenEntry

The IMSLogon::OpenEntry method opens a folder or message object and returns a pointer to the object to provide further access.

Quick Info

See IMSLogon : IUnknown.

HRESULT OpenEntry(
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  LPCIID lpInterface,
  ULONG ulOpenFlags,
  ULONG FAR * lpulObjType,
  LPUNKNOWN FAR * lppUnk
);

Parameters

cbEntryID
[in] Size, in bytes, of the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the address of the entry identifier of the folder or message object to open.
lpInterface
[in] Pointer to the interface identifier (IID) for the object. Passing NULL indicates the object is cast to the standard interface for such an object. The lpInterface parameter can also be set to an identifier for an appropriate interface for the object.
ulOpenFlags
[in] Bitmask of flags that controls how the object is opened. The following flags can be set:
MAPI_BEST_ACCESS
The object should be opened with the maximum permissions allowed for the user and the maximum client application access. For example, if the client has read/write access, the object is opened with read/write access; if the client has read-only access, the object is opened with read-only access. The client can retrieve the access level by getting the PR_ACCESS_LEVEL property.
MAPI_DEFERRED_ERRORS
The call is allowed to succeed even if the underlying object is not accessible to the calling application. If the object is not accessible, some subsequent call to the object might return an error.
MAPI_MODIFY
Requests read/write access. By default, objects are created with read-only access, and clients should not work on the assumption that read/write access has been granted.
lpulObjType
[out] Pointer to the type of the opened object.
lppUnk
[out] Pointer to the pointer to the opened object.

Return Value

S_OK
The call succeeded and has returned the expected value or values.

Remarks

MAPI calls the IMSLogon::OpenEntry method to open a folder or a message in a message store. MAPI passes in the entry identifier of the object to open; the message store provider should return a pointer providing further access to the object in the lppUnk parameter.

Before MAPI calls IMSLogon::OpenEntry, it first determines that the given message or folder entry identifier matches one registered by this message store provider. For more information on how store providers register entry identifiers, see IMAPISupport::SetProviderUID.

IMSLogon::OpenEntry is identical to the IMsgStore::OpenEntry method of the message store object but is called by MAPI when processing an IMAPISession::OpenEntry method call instead of being called by a client. Objects opened using IMSLogon::OpenEntry should be treated exactly the same as objects opened with the message store object; in particular, objects opened using this call should be invalidated when the message store object is released.

See Also

IMAPISupport::SetProviderUID, IMsgStore::OpenEntry


IMSLogon::OpenStatusEntry

The IMSLogon::OpenStatusEntry method opens a status object.

Quick Info

See IMSLogon : IUnknown.

HRESULT OpenStatusEntry(
  LPCIID lpInterface,
  ULONG ulFlags,
  ULONG FAR * lpulObjType,
  LPVOID FAR * lppEntry
);

Parameters

lpInterface
[in] Pointer to the interface identifier (IID) for the status object to open. Passing NULL indicates the standard interface for the object is returned, in this case the IMAPIStatus interface. The lpInterface parameter can also be set to an identifier for an appropriate interface for the object.
ulFlags
[in] Bitmask of flags that controls how the status object is opened. The following flag can be set:
MAPI_MODIFY
Requests read/write access. By default, objects are created with read-only access, and client applications should not work on the assumption that read/write access has been granted.
lpulObjType
[out] Pointer to the type of the opened object.
lppEntry
[out] Pointer to the pointer to the opened object.

Return Value

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Message store providers implement the IMSLogon::OpenStatusEntry method to open a status object. This status object is then used to enable clients to call IMAPIStatus methods; for example, clients can use the IMAPIStatus::SettingsDialog method to reconfigure the message store logon session or the IMAPIStatus::ValidateState method to validate the state of the message store logon session.

See Also

IMAPIStatus : IMAPIProp, IMAPIStatus::SettingsDialog, IMAPIStatus::ValidateState


IMSLogon::Unadvise

The IMSLogon::Unadvise method removes an object's registration for notification of message store changes previously established with a call to the IMSLogon::Advise method.

Quick Info

See IMSLogon : IUnknown.

HRESULT Unadvise(
  ULONG ulConnection
);

Parameters

ulConnection
[in] Number of the registration connection returned by a call to IMSLogon::Advise.

Return Value

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Message store providers implement the IMSLogon::Unadvise method to release the pointer to the advise sink object passed in the lpAdviseSink parameter in the previous call to IMSLogon::Advise, thereby canceling a notification registration. As part of discarding the pointer to the advise sink object, the object's IUnknown::Release method is called. Generally, Release is called during the Unadvise call, but if another thread is in the process of calling the IMAPIAdviseSink::OnNotify method for the advise sink object, the Release call is delayed until the OnNotify method returns.

See Also

IMAPIAdviseSink::OnNotify, IMSLogon::Advise


IMSProvider : IUnknown

The IMSProvider interface provides access to a message store provider through a message store provider object. This message store provider object is returned at provider logon by the message store provider's MSProviderInit entry point function. The message store provider object is primarily used by client applications and the MAPI spooler to open message stores.

Quick Info

Header file: | MAPISPI.H
Exposed by: | Message store provider objects
Implemented by: | Message store providers
Called by: | MAPI and the MAPI spooler
Interface identifier: | IID_IMSProvider
Pointer type: | LPMSPROVIDER

Vtable Order

Shutdown | Closes down a message store provider in an orderly fashion.
Logon | Logs MAPI on to one instance of a message store provider.
SpoolerLogon | Logs the MAPI spooler on to a message store.
CompareStoreIDs | Compares two message store entry identifiers to determine if they refer to the same store object.

Remarks

MAPI uses one message store provider object per session, no matter how many message stores are opened by the store provider. If a second MAPI session logs on to any open stores, MAPI calls MSProviderInit a second time to create a new message store provider object for that session to use.

A message store provider object must contain the following to operate correctly:

  • An lpMalloc memory-allocation routine pointer for use by all stores opened using this provider object.
  • The lpfAllocateBuffer, lpfAllocateMore, and lpfFreeBuffer routine pointers to the MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer memory allocation functions.
  • A linked list of all the stores opened using this provider object and not yet closed.


IMSProvider::CompareStoreIDs

The IMSProvider::CompareStoreIDs method compares two message store entry identifiers to determine if they refer to the same store object.

Quick Info

See IMSProvider : IUnknown.

HRESULT CompareStoreIDs(
  ULONG cbEntryID1,
  LPENTRYID lpEntryID1,
  ULONG cbEntryID2,
  LPENTRYID lpEntryID2,
  ULONG ulFlags,
  ULONG FAR * lpulResult
);

Parameters

cbEntryID1
[in] Size, in bytes, of the entry identifier pointed to by the lpEntryID1 parameter.
lpEntryID1
[in] Pointer to the first entry identifier to be compared.
cbEntryID2
[in] Size, in bytes, of the entry identifier pointed to by the lpEntryID2 parameter.
lpEntryID2
[in] Pointer to the second entry identifier to be compared.
ulFlags
Reserved; must be zero.
lpulResult
[out] Pointer to the returned result of the comparison; this variable is TRUE if the two entry identifiers refer to the same object, and FALSE otherwise.

Return Value

S_OK
The call succeeded and has returned the expected value or values.

Remarks

MAPI calls the IMSProvider::CompareStoreIDs method while processing a call to the IMAPISession::OpenMsgStore method. CompareStoreIDs is called at this point to determine which profile section, if any, is associated with the message store being opened. A CompareStoreIDs call can be made when no message stores are open for a particular store provider. In addition, MAPI also calls CompareStoreIDs while processing a store provider call to the IMAPISupport::OpenProfileSection method.

The entry identifiers compared by CompareStoreIDs are both for the current store provider's dynamic-link library (DLL) and are both unwrapped store entry identifiers. For more information on wrapping store entry identifiers, see IMAPISupport::WrapStoreEntryID.

Comparing entry identifiers is useful because an object can have more than one valid entry identifier; such a situation can occur, for example, after a new version of a message store provider is installed.

See Also

IMAPISession::OpenMsgStore, IMAPISupport::OpenProfileSection, IMAPISupport::WrapStoreEntryID


IMSProvider::Logon

The IMSProvider::Logon method logs MAPI on to one instance of a message store provider.

Quick Info

See IMSProvider : IUnknown.

HRESULT Logon(
  LPMAPISUP lpMAPISup,
  ULONG ulUIParam,
  LPTSTR lpszProfileName,
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  ULONG ulFlags,
  LPCIID lpInterface,
  ULONG FAR * lpcbSpoolSecurity,
  LPBYTE FAR * lppbSpoolSecurity,
  LPMAPIERROR FAR * lppMAPIError,
  LPMSLOGON FAR * lppMSLogon,
  LPMDB FAR * lppMDB
);

Parameters

lpMAPISup
[in] Pointer to the current MAPI support object for the message store.
ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays.
lpszProfileName
[in] Pointer to a string containing the name of the profile being used for store provider logon. This string can be displayed in dialog boxes, written out to a log file, or simply ignored. It must be in Unicode format if the MAPI_UNICODE flag is set in the ulFlags parameter.
cbEntryID
[in] Size, in bytes, of the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier for the message store. Passing NULL in lpEntryID indicates that a message store has not yet been selected and that dialog boxes enabling the user to select a message store can be presented.
ulFlags
[in] Bitmask of flags that controls how the logon is performed. The following flags can be set:
MAPI_DEFERRED_ERRORS
The call is allowed to succeed even if the underlying object is not accessible to the calling implementation. If the object is not accessible, some subsequent call to the object might return an error.
MAPI_UNICODE
The passed-in strings are in Unicode format. If MAPI_UNICODE is not set, the strings are in ANSI format.
MDB_NO_DIALOG
Prevents display of logon dialog boxes. If this flag is set, the error value MAPI_E_LOGON_FAILED is returned if logon is unsuccessful. If this flag is not set, the message store provider can prompt the user to correct a name or password, to insert a disk, or to perform other actions necessary to establish connection to the store.
MDB_NO_MAIL
The message store should not be used for sending or receiving mail. The flag signals MAPI not to notify the MAPI spooler that this message store is being opened. If this flag is set, and the message store is tightly coupled with a transport provider, then the provider does not need to call the IMAPISupport::SpoolerNotify method.
MDB_TEMPORARY
Logs on the store so that information can be retrieved programmatically from the profile section, without use of dialog boxes. This flag instructs MAPI that the store is not to be added to the message store table and that the store cannot be made permanent. If this flag is set, message store providers do not need to call the IMAPISupport::ModifyProfile method.
MDB_WRITE
Requests read/write access.
lpInterface
[in] Pointer to the interface identifier (IID) for the message store to log on to. Passing NULL indicates the MAPI interface for the message store is returned — that is, the IMsgStore interface. The lpInterface parameter can also be set to an identifier for an appropriate interface for the message store, for example IID_IUnknown or IID_IMAPIProp.
lpcbSpoolSecurity
[out] Pointer to the variable where the store provider returns the size, in bytes, of the validation data in the lppbSpoolSecurity parameter.
lppbSpoolSecurity
[out] Pointer to the pointer to the returned validation data. This validation data is provided so the IMSProvider::SpoolerLogon method can log the MAPI spooler on to the same store as the message store provider.
lppMAPIError
[out] Pointer to a pointer to the returned MAPIERROR structure, if any, containing version, component, and context information for an error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.
lppMSLogon
[out] Pointer to the pointer to the message store logon object for MAPI to log on to.
lppMDB
[out] Pointer to the pointer to the message store object for the MAPI spooler and client applications to log on to.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_FAILONEPROVIDER
This provider cannot log on, but this error should not disable the service.
MAPI_E_LOGON_FAILED
A logon session could not be established.
MAPI_E_UNCONFIGURED
The profile does not contain enough information for the logon to complete. When this value is returned, MAPI calls the message store provider's message-service entry point function.
MAPI_E_USER_CANCEL
The user canceled the operation, typically by clicking the Cancel button in a dialog box.
MAPI_E_UNKNOWN_CPID
The server is not configured to support the client's code page.
MAPI_E_UNKNOWN_LCID
The server is not configured to support the client's locale information.
MAPI_W_ERRORS_RETURNED
The call succeeded, but the message store provider has error information available. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling.To get the error information from the provider, call the IMAPISession::GetLastError method.

Remarks

MAPI calls the IMSProvider::Logon method to do the majority of processing necessary to obtain access to a message store. Message store providers validate any user credentials necessary to access a particular store and return a message store object in the lppMDB parameter that the MAPI spooler and client applications can log on to.

In addition to the message store object returned for client and MAPI spooler use, the provider also returns a message store logon object for MAPI to use in controlling the opened store. The message store logon object and the message store object should be tightly linked inside the message store provider so each can affect the other. Usage of the store object and the logon object should be identical; there should be a one-to-one correspondence between the logon object and the store object such that the objects act as if they are one object exposing two interfaces. The two objects should also be created together and freed together.

The MAPI support object, created by MAPI and passed to the provider in the lpMAPISup parameter, provides access to functions in MAPI required by the provider. These include functions that save and retrieve profile information, access address books, and so on. The lpMAPISup pointer can be different for each store that is opened. While processing calls for a message store after logon, the store provider should use the lpMAPISup variable specific to that store. For any Logon call that opens a message store and succeeds in creating a message store logon object, the provider must save a pointer to the MAPI support object in the store logon object and must call the IUnknown::AddRef method to add a reference for the support object.

The ulUIParam parameter should be used if the provider presents dialog boxes during the Logon call. However, dialog boxes should not be presented if ulFlags contains the MDB_NO_DIALOG flag. If a user interface needs to be called but ulFlags does not allow it, or if for some other reason a user interface cannot be displayed, the provider should return MAPI_E_LOGON_FAILED. If Logon displays a dialog box and the user cancels logon, typically by clicking the dialog box's Cancel button, the provider should return MAPI_E_USER_CANCEL.

The lpEntryID parameter can either be NULL or point to an unwrapped store entry identifier previously created by this message store. If lpEntryID points to an unwrapped entry identifier, that entry identifier can come from one of several places:

  • It can be an entry identifier that the store provider previously wrapped and wrote to the profile section as a PR_ENTRYID property.
  • It can be an entry identifier that the provider previously wrapped and returned to a calling client as a PR_STORE_ENTRYID property.
  • It can be an entry identifier that the provider previously wrapped and returned to a calling client as the PR_ENTRYID property of a message store object.

In any of these cases, it is possible that the entry identifier was created on a different computer than the one currently being used.

When lpEntryID is not NULL, it should contain all of the information needed to identify and locate the message store. This information can include network volume names, phone numbers, user account names, and so on. If the connection to the store cannot be made using the data in the entry identifier, then the store provider should display a dialog box that enables the user to select the store to be opened. A dialog box might be required, for example, if a server has been renamed, an account name has changed, or portions of the network are not available.

When lpEntryID is NULL, the message store to use has not yet been selected. The provider can still access a store without displaying a dialog box if it supports further methods to specify the store. For example, the provider can check its initialization file, or it can look for additional properties that were placed in its or its message service's profile section at configuration.

If a provider finds that all the required information is not in the profile, it should return MAPI_E_UNCONFIGURED so that MAPI calls the provider's message service entry point function to enable the user to select a store, or even to create one, and to enter an account name and password as needed. MAPI automatically creates a new profile section for a new store; this new profile section can be temporary or permanent, depending on how it has been added. If the store provider calls the IMAPISupport::ModifyProfile method, the new profile section becomes permanent and the store is added to the list of message stores returned by the IMAPISession::GetMsgStoresTable method.

The lpInterface parameter specifies the IID of the interface required for the newly opened store object. Passing NULL in lpInterface specifies that the MAPI message store interface, IMsgStore, is required. Passing the message store object, IID_IMsgStore, also specifies that IMsgStore is required. If IID_IUnknown is passed in lpInterface, the provider should open the store using whatever interface derived from IUnknown that is best for the provider; again, this is typically IMsgStore. When IID_IUnknown is passed, after the store open operation succeeds the calling implementation uses the IUnknown::QueryInterface method to select an interface.

The IMSProvider::Logon call should return sufficient information, such as a path to the store and credentials for accessing the store, to allow the MAPI spooler to log on to the same store the store provider does without presenting a dialog box. The lpcbSpoolSecurity and lppbSpoolSecurity parameters are used to return this information. The provider allocates the memory for this data by passing a pointer to a buffer in the MSProviderInit function's lpfAllocateBuffer parameter; the provider places the size of this buffer in lpcbSpoolSecurity.

MAPI frees this buffer when appropriate. If the MAPI spooler's logon to the store can be accomplished from the information in the profile section alone, the provider can return NULL in lppbSpoolSecurity and zero for the information's size in lpcbSpoolSecurity. The MAPI spooler logon occurs as part of a different process than the store logon; because the buffer holding the passed information gets copied between processes, it might not be in memory at the same location for the MAPI spooler process as for the store provider process. Therefore, a provider shouldn't put addresses into this buffer. For more information on MAPI spooler logon, see IMSProvider::SpoolerLogon.

Most store providers use the IMAPISession::OpenProfileSection method of the support object passed in the lpMAPISup parameter for saving and retrieving user credentials and options. OpenProfileSection enables a store provider to save additional arbitrary information in a profile section and associate it with a particular resource. For example, a store provider can save the user account name and password associated with a resource and any paths or other necessary information needed to access that resource.

Properties with property identifiers 0x6600 through 0x67FF are secure properties available to the provider for its own use to store private data in profile sections. For more information on the uses of properties in profile section objects, see IProfSect : IMAPIProp.

In addition to any private data in properties with identifiers 0x6600 through 0x67FF, the store provider should provide information for the PR_DISPLAY_NAME property in its profile section. It should place in PR_DISPLAY_NAME the display name of the provider itself — an identifying string displayed to users so they can distinguish this message store from others they might have access to — for example, "Microsoft Personal Information Store." PR_DISPLAY_NAME commonly contains a server name, user account name, or path.

Some profile section properties are visible in the message store table; others are visible during setup, installation, and configuration of the MAPI subsystem. The provider typically provides information for these visible properties both for a new profile section, which does not yet include saved credentials or private information, and when it finds that property information has changed. For more information on profile sections, see IMAPISupport::OpenProfileSection.

After successfully logging a user on, and before returning to MAPI, the store provider should create the array of properties for the status row for the resource and call IMAPISupport::ModifyStatusRow.

Logon calls that open message stores already open for the current MAPI session skip much of the processing described previously. These calls do not create status rows, do not return message store logon objects, do not call AddRef for the MAPI support object, and do not return data for MAPI spooler logon. These calls do return S_OK and do return a message store object with the interface requested.

To detect such calls, the provider should maintain a list in the message store provider object of stores already open for this provider object. When processing a Logon call, the provider should scan this list of open stores and determine if the store to be logged onto is already open. If it is, user credentials do not need to be checked and dialog box display should be avoided if possible. If dialog boxes must be displayed, the provider should check information returned to see whether a store has been opened a second time. In addition, the provider should check for duplicate openings using lpEntryID at the beginning of Logon call processing.

Standard processing for a Logon call that accesses an open store is as follows:

  1. The store provider calls AddRef for the existing store object if the new interface being requested is the same as the interface for the existing store. Otherwise, it calls QueryInterface to get the new interface. If the new interface isn't one the store supports, the provider should return the error value MAPI_E_INTERFACE_NOT_SUPPORTED.
  2. The provider returns a pointer to the required interface of the existing store object in lppMDB.
  3. The provider returns NULL in lppMSLogon.
  4. The provider should not open the profile for the support object passed in the call. Neither should it register a provider unique identifier, register a status row, nor return MAPI spooler logon data.
  5. The provider should not call AddRef for the support object, because it does not require a pointer to the object.

Whenever possible, providers should return appropriate error and warning strings for Logon calls because doing so greatly eases the burden of users determining why something did not work. To do so, a provider sets the members in the MAPIERROR structure. MAPI looks for, uses, and releases the MAPIERROR structure if it is returned by a provider.

Memory for this MAPIERROR structure should be allocated using the buffer passed in lpfAllocateBuffer on the MSProviderInit call. Any error strings contained in the returned structure should be in Unicode format if MAPI_UNICODE is set in the Logon ulFlags; otherwise, they should be in the ANSI character set.

For most error values returned from Logon, MAPI disables the message services to which the failing provider belongs. MAPI will not call any providers belonging to those services for the rest of the life of the MAPI session. In contrast, when Logon returns the MAPI_E_FAILONEPROVIDER error value from its logon, MAPI does not disable the message service to which the provider belongs. Logon should return MAPI_E_FAILONEPROVIDER if it encounters an error that does not warrant disabling the entire service for the life of the session. For example, a provider might return this error when it does not allow the display of a user interface and a required password is unavailable.

If a provider returns MAPI_E_UNCONFIGURED from its logon, MAPI will call the provider's message service entry function and then retry the logon. MAPI passes MSG_SERVICE_CONFIGURE as the context, to give the service a chance to configure itself. If the client has chosen to allow a user interface on the logon, the service can present its configuration property sheet so the user can enter configuration information.

See Also

IMAPISession::GetMsgStoresTable, IMAPISession::OpenMsgStore, IMAPISession::OpenProfileSection, IMAPISupport::ModifyProfile, IMAPISupport::ModifyStatusRow, IMsgStore : IMAPIProp, IMSProvider::SpoolerLogon, IProfSect : IMAPIProp, MAPIERROR, MSProviderInit


IMSProvider::Shutdown

The IMSProvider::Shutdown method closes down a message store provider in an orderly fashion.

Quick Info

See IMSProvider : IUnknown.

HRESULT Shutdown(
  ULONG FAR * lpulFlags
);

Parameters

lpulFlags
Reserved; must be a pointer to zero.

Return Value

S_OK
The call succeeded and has returned the expected value or values.

Remarks

MAPI calls the IMSProvider::Shutdown method just before releasing the message store provider object. MAPI releases all logon objects for a provider before calling Shutdown for that provider.


IMSProvider::SpoolerLogon

The IMSProvider::SpoolerLogon method logs the MAPI spooler on to a message store.

Quick Info

See IMSProvider : IUnknown.

HRESULT SpoolerLogon(
  LPMAPISUP lpMAPISup,
  ULONG ulUIParam,
  LPTSTR lpszProfileName,
  ULONG cbEntryID,
  LPENTRYID lpEntryID,
  ULONG ulFlags,
  LPCIID lpInterface,
  ULONG cbSpoolSecurity,
  LPBYTE lpbSpoolSecurity,
  LPMAPIERROR FAR * lppMAPIError,
  LPMSLOGON FAR * lppMSLogon,
  LPMDB FAR * lppMDB
);

Parameters

lpMAPISup
[in] Pointer to the MAPI support object for the message store.
ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays.
lpszProfileName
[in] Pointer to a string containing the name of the profile being used for the MAPI spooler logon. This string can be displayed in dialog boxes, written out to a log file, or simply ignored. It must be in Unicode format if the MAPI_UNICODE flag is set in the ulFlags parameter.
cbEntryID
[in] Size, in bytes, of the entry identifier pointed to by the lpEntryID parameter.
lpEntryID
[in] Pointer to the entry identifier for the message store. Passing NULL in the lpEntryID parameter indicates that a message store has not yet been selected and that dialog boxes enabling the user to select a message store can be presented.
ulFlags
[in] Bitmask of flags that controls how the logon is performed. The following flags can be set:
MAPI_DEFERRED_ERRORS
The call is allowed to succeed even if the underlying object is not accessible to the calling implementation. If the object is not accessible, some subsequent call to the object might return an error.
MAPI_UNICODE
The passed-in strings are in Unicode format. If MAPI_UNICODE is not set, the strings are in ANSI format.
MDB_NO_DIALOG
Prevents display of logon dialog boxes. If this flag is set, the error value MAPI_E_LOGON_FAILED is returned if logon is unsuccessful. If this flag is not set, the message store provider can prompt the user to correct a name or password, to insert a disk, or to perform other actions necessary to establish connection to the store.
MDB_WRITE
Requests read/write access.
lpInterface
[in] Pointer to the interface identifier (IID) for the message store to log on to. Passing NULL indicates the MAPI interface for the message store is returned — that is, the IMsgStore interface. The lpInterface parameter can also be set to an identifier for an appropriate interface for the message store, for example IID_IUnknown or IID_IMAPIProp.
cbSpoolSecurity
[in] Pointer to the size, in bytes, of validation data in the lppbSpoolSecurity parameter.
lpbSpoolSecurity
[in] Pointer to a pointer to validation data. The SpoolerLogon method uses this data to log the MAPI spooler on to the same store as the message store provider previously logged on to using the IMSProvider::Logon method.
lppMAPIError
[out] Pointer to a pointer to the returned MAPIERROR structure, if any, containing version, component, and context information for an error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.
lppMSLogon
[out] Pointer to the pointer to the message store logon object for MAPI to log on to.
lppMDB
[out] Pointer to the pointer to the message store object for the MAPI spooler and client applications to log on to.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_UNCONFIGURED
The profile does not contain enough information for the logon to complete. When this value is returned, MAPI calls the message store provider's message service entry point function.
MAPI_W_ERRORS_RETURNED
The call succeeded, but the message store provider has error information available. When this warning is returned, the call should be handled as successful. To test for this warning, use the HR_FAILED macro. See Using Macros for Error Handling. To get the error information from the provider, call the IMAPISession::GetLastError method.

Remarks

The MAPI spooler calls the IMSProvider::SpoolerLogon method to log on to a message store. The MAPI spooler should use the message store object returned by the message store provider in the lppMDB parameter during and after logon.

For consistency with the IMSProvider::Logon method, the provider also returns a message store logon object in the lppMSLogon parameter. Usage of the store object and the logon object are identical for usual store logon, because there is a one-to-one correspondence between the logon object and the store object; you can think of the logon and store objects as one object exposing two interfaces. The two objects are created together and freed together.

The store provider should internally mark the returned message store object to indicate that the store is being used by the MAPI spooler. Some of the methods for this store object behave differently than for the message store object provided to client applications. Keeping this internal mark is the most common way of triggering the behavior specific to the MAPI spooler.

See Also

IMSProvider::Logon, MAPIERROR


IPersistMessage : IUnknown

The IPersistMessage interface is used by form viewers to handle the storage of a form and to transition between the various states.

Quick Info

Header file: | MAPIFORM.H
Exposed by: | Persist message objects
Implemented by: | Form objects
Called by: | Form viewers
Interface identifier: | IID_IPersistMessage
Pointer type: | LPPERSISTMESSAGE

Vtable Order

GetLastError | Returns a MAPIERROR structure containing information about the previous error in the form object.
GetClassID | Returns an identifier representing the form server that can manage the form.
IsDirty | Checks the form for changes made since the last save.
InitNew | Initializes a new message.
Load | Loads the form for a specified message.
Save | Saves a revised form back to the message from which it was loaded or created.
SaveCompleted | Notifies the form that a save operation has been completed.
HandsOffMessage | Causes the form to release its current message.

Remarks

All forms are required to implement the IPersistMessage interface.

IPersistMessage works similarly to the OLE IPersistStorage interface; for more information on the IPersistStorage methods, and on working with storage objects in general, see the OLE Programmer's Reference.


IPersistMessage::GetClassID

The IPersistMessage::GetClassID method returns an identifier representing the form server that can manage the form.

Quick Info

See IPersistMessage : IUnknown.

HRESULT GetClassID(
  LPCLSID lpClassID
);

Parameters

lpClassID
[in, out] Pointer to the class identifier (CLSID) of the form.

Return Value

S_OK
The class identifier was successfully returned.

Remarks

The IPersisMessge::GetClassID method sets the contents of the lpClassID parameter to the form server's class identifier and returns S_OK. When a form viewer calls GetClassID and it returns successfully, the form is placed in the Uninitialized state.

For more information on how class identifiers are used with structured storage objects, see the documentation for the IPersist::GetClassID method in the OLE Programmer's Reference.


IPersistMessage::GetLastError

The IPersistMessage::GetLastError method returns a MAPIERROR structure containing information about the previous error in the form object.

Quick Info

See IPersistMessage : IUnknown.

HRESULT GetLastError(
  HRESULT hResult,
  ULONG ulFlags,
  LPMAPIERROR FAR * lppMAPIError
);

Parameters

hResult
[in] HRESULT data type containing the error value generated in the previous method call.
ulFlags
[in] Bitmask of flags that controls the type of the returned strings. The following flag can be set:
MAPI_UNICODE
The strings in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppMAPIError
[out] Pointer to a pointer to a MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if the form cannot supply a MAPIERROR structure with appropriate information.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the address book provider does not support Unicode, or MAPI_UNICODE was not set and the address book provider only supports Unicode.

Remarks

Form objects implement the IPersistMessage::GetLastError method to supply information about a prior method call that failed. Form viewers can provide their users with detailed information about the error by including the data from the MAPIERROR structure in a dialog box.

A call to GetLastError does not affect the state of the form. When GetLastError returns, the form remains in the state that it was in before the call was made.

Notes to Callers

You can make use of the MAPIERROR structure pointed to by the lppMAPIError parameter — if the form supplies one — only if GetLastError returns S_OK. Sometimes the form cannot determine what the last error was or has nothing more to report about the error. In this situation, the form returns a pointer to NULL in lppMAPIError instead.

For more information about the GetLastError method, see Using Extended Errors.

See Also

MAPIERROR, MAPIFreeBuffer


IPersistMessage::HandsOffMessage

The IPersistMessage::HandsOffMessage method causes the form to release its current message.

Quick Info

See IPersistMessage : IUnknown.

HRESULT HandsOffMessage();

Parameters

None

Return Values

S_OK
The message was successfully released.

Remarks

Forms transition into two Hands Off states:

  • Hands Off After Save
  • Hands Off From Normal

When a form is in either of these states, it is in the process of being stored permanently.

Notes to Implementers

When a form viewer calls the IPersistMessage::HandsOffMessage method while your form is in the Normal or No Scribble state, recursively call HandsOffMessage on each message embedded in the current message and IPersistStorage::HandsOffStorage on each OLE object embedded in the current message. Then release the current message and all embedded messages and OLE objects. If your form was in the Normal state, transition to the Hands Off From Normal state. If your form was in the No Scribble state, transition to the Hands Off After Save state. After a successful transition, call the message's IUnknown::Release method and return S_OK.

When a form viewer calls HandsOffMessage while your form is in either of the Hands Off states, return E_UNEXPECTED.

For more information about the different states of a form, see Form States. For more information on working with the Hands Off state of storage objects, see the IPersistStorage::HandsOffStorage method documented in the OLE Programmer's Reference.


IPersistMessage::InitNew

The IPersistMessage::InitNew method initializes a new message.

Quick Info

See IPersistMessage : IUnknown.

HRESULT InitNew(
  LPMAPIMESSAGESITE pMessageSite,
  LPMESSAGE pMessage
);

Parameters

pMessageSite
[in] Pointer to the message site that the form will use to work with the message in the viewer.
pMessage
[in] Pointer to the new message.

Return Values

S_OK
The new message was successfully initialized.

Remarks

Form viewers call the IPersistMessage::InitNew method when the user composes a new message belonging to a message class that is handled by the form. If the form object has a valid user interface pointer, the user interface for the message object should be displayed.

InitNew should not be called when your form is in any state except the Uninitialized state. If the form is in one of the other states when InitNew is called, return E_UNEXPECTED.

Notes to Implementers

Typically, messages that have unsaved properties are marked as dirty so that the client can display a dialog box prompting the user whether or not these properties should be saved. If the user indicates that a message should be saved, save the data, mark the message as clean, and exit normally.

However, if processing for your newly initialized messages includes setting one or more computed properties and it is important for those properties to be saved, do not mark the messages as dirty. Because computed properties should be invisible to users, no dialog box should be displayed.

If your form has a reference to an active message site other than the one that is passed into InitNew, release the original site because it will no longer be used. Store the pointers to the message site and message from the pMessageSite and pMessage parameters and call both objects' IUnknown::AddRef methods to increment their reference counts.

Set the PR_MESSAGE_FLAGS and PR_MSG_STATUS properties for the new message to something appropriate for your message class. Many message classes, for example, set PR_MESSAGE_FLAGS to MSGFLAG_UNSENT for new messages.

Before returning, transition the form to the Normal state if no errors have occurred. Send a new message notification to all registered viewers by calling their IMAPIViewAdviseSink::OnNewMessage methods and return S_OK.

Notes to Callers

After you have made a successful call to InitNew, you can assume that the following required properties, and no others, have been set for the form:

PR_DELETE_AFTER_SUBMIT

PR_IMPORTANCE

PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED

PR_PRIORITY

PR_READ_RECEIPT_REQUESTED

PR_SENSITIVITY

PR_SENTMAIL_ENTRYID

For more information about the states of forms, see Form States. For more information on how storage objects are initialized, see the documentation for IPersistStorage::InitNew in the OLE Programmer's Reference.


IPersistMessage::IsDirty

The IPersistMessage::IsDirty method checks the form for changes made since the last save.

Quick Info

See IPersistMessage : IUnknown.

HRESULT IsDirty();

Parameters

None

Return Values

S_OK
The form has had changes made since it was last saved.
S_FALSE
The form has not had changes made since it was last saved.

Remarks

Form viewers call the IPersistMessage::IsDirty method to determine whether the message has unsaved data.

For more information, see the documentation for the following OLE methods in the OLE Programmer's Reference:

IPersistStorage::IsDirty

IPersistStream::IsDirty

IPersistFile::IsDirty


IPersistMessage::Load

The IPersistMessage::Load method loads the form for a specified message.

Quick Info

See IPersistMessage : IUnknown.

HRESULT Load(
  LPMESSAGESITE pMessageSite,
  LPMESSAGE pMessage,
  ULONG ulMessageStatus,
  ULONG ulMessageFlags
);

Parameters

pMessageSite
[in] Pointer to the message site for the form to be loaded.
pMessage
[in] Pointer to the message for which the form should be loaded.
ulMessageStatus
[in] Bitmask of client-defined or provider-defined flags — copied from the message's PR_MSG_STATUS property — that provides information on the state of the message.
ulMessageFlags
[in] Bitmask of flags — copied from the message's PR_MESSAGE_FLAGS property — that provides further information on the state of the message.

Return Values

S_OK
The form was successfully loaded.

Remarks

Form viewers call the IPersistMessage::Load method to load a form for an existing message.

Notes to Implementers

Load is called only when a form is in one of the following states:

  • Uninitialized
  • Hands Off After Save
  • Hands Off From Normal

If a form viewer calls Load while the form is in any other state, the method returns E_UNEXPECTED.

If your form has a reference to an active message site other than the one that is passed into Load, release the original site because it will no longer be used. Store the pointers to the message site and message from the pMessageSite and pMessage parameters and call both objects' IUnknown::AddRef methods to increment their reference counts.

After AddRef has completed, store the properties from the ulMessageStatus and ulMessageFlags parameters into the form. Transition the form to its Normal state before displaying it and notify registered viewers by calling their IMAPIViewAdviseSink::OnNewMessage methods.

If no errors occur, return S_OK.

For more information on loading storage objects, see the documentation for the following methods in the OLE Programmer's Reference:

IPersistStorage::Load

IPersistStream::Load

IPersistFile::Load

See Also

PR_MESSAGE_FLAGS, PR_MSG_STATUS


IPersistMessage::Save

The IPersistMessage::Save method saves a revised form back to the message from which it was loaded or created.

Quick Info

See IPersistMessage : IUnknown.

HRESULT Save(
  LPMESSAGE pMessage,
  ULONG fSameAsLoad
);

Parameters

pMessage
[in] Pointer to the message.
fSameAsLoad
[in] Value that is set to TRUE if the message pointed to by pMessage is the message from which the form was loaded or created, and FALSE otherwise.

Return Values

S_OK
The form was successfully saved.

Remarks

Form viewers call the IPersistMessage::Save method to save a revised form back to the message from which it was loaded or created.

Save should only be called when the form is its Normal state.

Notes to Implementers

Do not commit the saved changes; it is up to the caller to perform the commit. Never make changes to the properties belonging to the form's message except during the Save call.

If fSameAsLoad is set to TRUE, you can save the changes to the form's existing message. If fSameAsLoad is set to FALSE, you must copy all of the properties from the original message into the message pointed to by pMessage before performing the save. Use the original message's IMAPIProp::CopyTo method to copy the properties.

When all of the properties have been copied, enter the No Scribble state. If no errors occur, return S_OK. Otherwise, return the error from the failed action.

If Save is called when the form is in any state other than Normal, return E_UNEXPECTED.

For more information on saving storage objects, see the documentation on the IPersistStorage methods in the OLE Programmer's Reference.


IPersistMessage::SaveCompleted

The IPersistMessage::SaveCompleted method notifies the form that a save operation has been completed.

Quick Info

See IPersistMessage : IUnknown.

HRESULT SaveCompleted(
  LPMESSAGE pMessage
);

Parameters

pMessage
[in] Pointer to the newly saved message.

Return Values

S_OK
The notification was successful.
E_INVALIDARG
The pMessage parameter is NULL and the form is either in the Hands Off From Normal or Hands Off After Save state.
E_UNEXPECTED
The form is not in one of the following states:
  • Hands Off From Normal
  • Hands Off After Save
  • No Scribble

Remarks

The IPersistMessage::SaveCompleted method is called by a form viewer to notify the form that all pending changes have been saved. SaveCompleted should only be called when the form is in one of the following states:

  • Hands Off From Normal
  • Hands Off After Save
  • No Scribble

Notes to Implementers

There are several possible actions that the SaveCompleted method can perform, depending on what the message pointer parameter contains, and what state the message is in. However, when an action is successful, always save the current state of the message pointed to by the pMessage parameter and transition the form to its Normal state.

The following table describes the variables that affect the actions you should take in your implementation of SaveCompleted:

Condition | Action
The pMessage parameter is NULL and the fSameAsLoad parameter to Save was set to TRUE. | Call the IMAPIViewAdviseSink::OnSaved method of all registered viewers, mark the form as clean, and return S_OK.
The pMessage parameter is NULL and the fSameAsLoad parameter to Save was set to FALSE. | Return S_OK.
The form is in the Hands Off From Normal state. | Release the current message and replace it with the message pointed to by pMessage. Call the replacement message's IUnknown::AddRef method and return S_OK.
The form is in the Hands Off After Save state. | Call the IMAPIViewAdviseSink::OnSaved method of all registered viewers, mark the form as clean, and return S_OK.
The form is in the No Scribble state. | Release the current message and replace it with the message pointed to by pMessage. Call the replacement message's IUnknown::AddRef method. Call the IMAPIViewAdviseSink::OnSaved method of all registered viewers, mark the form as clean, and return S_OK.
The form is in one of the Hands Off states and the pMessage parameter is set to NULL. | Return E_INVALIDARG.
The form is in a state other than one of the Hands Off states or the No Scribble state. | Return E_UNEXPECTED.

For more information on saving storage objects, see the documentation for one of the following methods in the OLE Programmer's Reference:

IPersistFile::SaveCompleted

IPersistStorage::SaveCompleted


IProfAdmin : IUnknown

The IProfAdmin interface supports the administration of profiles.

Quick Info

Header file: | MAPIX.H
Exposed by: | Profile administration object
Implemented by: | MAPI
Called by: | Client applications
Interface identifier: | IID_IProfAdmin
Pointer type: | LPPROFADMIN

Vtable Order

GetLastError | Returns a MAPIERROR structure containing information about the previous error occurring to a profile administration object.
GetProfileTable | Provides access to the profile table — a table with information about all of the available profiles.
CreateProfile | Creates a new profile.
DeleteProfile | Deletes a profile.
ChangeProfilePassword | Changes the password for a profile.
CopyProfile | Copies a profile.
RenameProfile | Assigns a new name to a profile.
SetDefaultProfile | Sets or clears a client's default profile.
AdminServices | Provides access to a message service administration object for making changes to the message services in a profile.


IProfAdmin::AdminServices

The IProfAdmin::AdminServices method provides access to a message service administration object for making changes to the message services in a profile.

Quick Info

See IProfAdmin : IUnknown.

HRESULT AdminServices(
  LPTSTR lpszProfileName,
  LPTSTR lpszPassword,
  ULONG ulUIParam,
  ULONG ulFlags,
  LPSERVICEADMIN FAR * lppServiceAdmin
);

Parameters

lpszProfileName
[in] Pointer to the name of the profile to be modified. The lpszProfileName parameter must not be NULL.
lpszPassword
[in] Pointer to the profile's password, or NULL if the profile does not require a password. If lpszPassword is NULL, the profile requires a password, and the MAPI_DIALOG flag is set in the ulFlags parameter; a dialog box is displayed to prompt the user for the password.
ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays.
ulFlags
[in] Bitmask of flags that controls the retrieval of the message service administration object. The following flags can be set:
MAPI_DIALOG
Allows the display of a user interface.
MAPI_UNICODE
The profile name and password are in Unicode format. If the MAPI_UNICODE flag is not set, they are in ANSI format.
lppServiceAdmin
[out] Pointer to a pointer to a message service administration object.

Return Values

S_OK
The message service administration object was successfully returned.
MAPI_E_LOGON_FAILED
The specified profile doesn't exist, or the password was wrong and a dialog box could not be displayed to the user requesting the correct password because MAPI_DIALOG was not set in ulFlags.
MAPI_E_USER_CANCEL
The user canceled the operation, typically by clicking the Cancel button in a dialog box.

Remarks

The IProfAdmin::AdminServices method provides access to a message service administration object for making configuration changes to the message services within a profile.

Profile passwords are not supported on all operating system platforms. On platforms that do not support profile passwords, the lpszPassword parameter can be NULL or a pointer to a zero-length string. Currently, Microsoft® Windows NT® and Microsoft® Windows® 95 do not support passwords; Microsoft® Windows® version 3.1 does.

Notes to Callers

Although you retrieve an IMsgServiceAdmin pointer by calling either this method or IMAPISession::AdminServices to retrieve an IMsgServiceAdmin pointer, call this method if you are strictly a configuration client and offer no messaging features. The IProfAdmin method does not create a session object and does not load any service providers, enhancing performance.

IProfAdmin::AdminServices cannot be used to create a profile. Therefore, you must specify an existing valid profile in lpszProfileName. If the specified profile does not exist, AdminServices returns MAPI_E_LOGON_FAILED.

The name of the profile and its password can be up to 64 characters in length and can include the following characters:

  • All alphanumeric characters, including accent characters and the underscore character.
  • Embedded spaces, but not leading or trailing spaces.

See Also

IMAPISession::AdminServices


IProfAdmin::ChangeProfilePassword

The IProfAdmin::ChangeProfilePassword method changes the password for a profile.

Quick Info

See IProfAdmin : IUnknown.

HRESULT ChangeProfilePassword(
  LPTSTR lpszProfileName,
  LPTSTR lpszOldPassword,
  LPTSTR lpszNewPassword,
  ULONG ulFlags
);

Parameters

lpszProfileName
[in] Pointer to the name of the profile associated with the password to be changed.
lpszOldPassword
[in] Pointer to the current password.
lpszNewPassword
[in] Pointer to the new password.
ulFlags
[in] Bitmask of flags that controls the type of the passed-in strings. The following flag can be set:
MAPI_UNICODE
The profile name and passwords are in Unicode format. If the MAPI_UNICODE flag is not set, these strings are in ANSI format.

Return Values

S_OK
The profile's password was successfully changed.
MAPI_E_LOGON_FAILED
The password pointed to by the lpszOldPassword parameter is incorrect.
MAPI_E_NO_SUPPORT
The operating system does not support passwords.

Remarks

The IProfAdmin::ChangeProfilePassword method replaces one profile password with another. ChangeProfilePassword does not display a user interface.

Not all operating systems support passwords for their profiles. ChangeProfilePassword returns MAPI_E_NO_SUPPORT if the operating system does not support passwords. Currently, Microsoft® Windows NT® Server and Microsoft® Windows® 95 do not support passwords; Microsoft® Windows® version 3.1 does.


IProfAdmin::CopyProfile

The IProfAdmin::CopyProfile method copies a profile.

Quick Info

See IProfAdmin : IUnknown.

HRESULT CopyProfile(
  LPTSTR lpszOldProfileName,
  LPTSTR lpszOldPassword,
  LPTSTR lpszNewProfileName,
  ULONG ulUIParam,
  ULONG ulFlags
);

Parameters

lpszOldProfileName
[in] Pointer to the name of the profile to copy.
lpszOldPassword
[in] Pointer to the password of the profile to copy.
lpszNewProfileName
[in] Pointer to the new name of the copied profile.
ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays.
ulFlags
[in] Bitmask of flags that controls how the profile is copied. The following flags can be set:
MAPI_DIALOG
Allows the display of a dialog box prompting the user for the correct password of the profile to copy. If this flag is not set, no dialog box is displayed.
MAPI_UNICODE
The profile names and password are in Unicode format. If the MAPI_UNICODE flag is not set, these strings are in ANSI format.

Return Values

S_OK
The profile was successfully copied.
MAPI_E_ACCESS_DENIED
The new profile name is the same as that of an existing profile.
MAPI_E_LOGON_FAILED
The password for the profile to copy is incorrect, and a dialog box could not be displayed to the user requesting the correct password because MAPI_DIALOG was not set in the ulFlags parameter.
MAPI_E_NOT_FOUND
The specified profile does not exist.
MAPI_E_USER_CANCEL
The user canceled the operation, typically by clicking the Cancel button in a dialog box.

Remarks

The IProfAdmin::CopyProfile method makes a copy of the profile pointed to by lpszOldProfileName, giving it the name pointed to by lpszNewProfileName. Copying a profile leaves the copy with the same password as the original.

The name of the original profile, its password, and the copy can be up to 64 characters in length and can include the following characters:

  • All alphanumeric characters, including accent characters and the underscore character.
  • Embedded spaces, but not leading or trailing spaces.

Profile passwords are not supported on all operating system platforms; on platforms that do not support profile passwords, lpszOldPassword can be NULL or a pointer to a zero-length string. Currently, Windows NT Server and Windows 95 do not support passwords; Windows version 3.1 does.

If lpszOldPassword is set to NULL, the profile to be copied requires a password, and the MAPI_DIALOG flag is set; a dialog box prompting the user to provide the password is displayed. If a password is required, but lpszOldPassword is set to NULL and the MAPI_DIALOG flag is not set, CopyProfile returns MAPI_E_LOGON_FAILED.


IProfAdmin::CreateProfile

The IProfAdmin::CreateProfile method creates a new profile.

Quick Info

See IProfAdmin : IUnknown.

HRESULT CreateProfile(
  LPTSTR lpszProfileName,
  LPTSTR lpszPassword,
  ULONG ulUIParam,
  ULONG ulFlags
);

Parameters

lpszProfileName
[in] Pointer to the name of the new profile.
lpszPassword
[in] Pointer to the password of the new profile.
ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays.
ulFlags
[in] Bitmask of flags that controls how the profile is created. The following flags can be set:
MAPI_DEFAULT_SERVICES
MAPI should populate the new profile with the message services that are included in the [Default Services] section of the MAPISVC.INF file.
MAPI_DIALOG
The configuration property sheets of each of the providers in the message services to be added can be displayed.
MAPI_UNICODE
The profile name and password are in Unicode format. If the MAPI_UNICODE flag is not set, these strings are in ANSI format.

Return Values

S_OK
The new profile was created.
MAPI_E_NO_ACCESS
The specified new profile already exists.

Remarks

The IProfAdmin::CreateProfile method creates a new profile.

Notes to Callers

You can call CreateProfile at application installation time or at any time during a session. When called at installation time, many of the configuration settings come from the MAPISVC.INF configuration file. When called during an active session, the settings come from the user who is prompted through a series of property sheets.

If the MAPI_DEFAULT_SERVICES flag is set in the ulFlags parameter, CreateProfile calls the message service entry point function for each message service in the [Default Services] section in the MAPISVC.INF file. Each message service entry point function is called with the ulContext parameter set to MSG_SERVICE_CREATE.

If both the MAPI_DIALOG and MAPI_DEFAULT_SERVICES flags are set, then the values in the ulUIParam and ulFlags parameters are also passed to the message service entry point function. The message service entry point functions are only called after all available information from the MAPISVC.INF file has been added to the profile.

The name of the new profile and its password can be up to 64 characters in length and can include the following characters:

  • All alphanumeric characters, including accent characters and the underscore character.
  • Embedded spaces, but not leading or trailing spaces.

Profile passwords are not supported on all operating system platforms; on platforms that do not support profile passwords, lpszPassword can be NULL or a pointer to a zero-length string. Currently, Windows NT Server and Windows 95 do not support passwords; Windows version 3.1 does.

See Also

IMsgServiceAdmin::ConfigureMsgService, IMsgServiceAdmin::CreateMsgService, MSGSERVICEENTRY


IProfAdmin::DeleteProfile

The IProfAdmin::DeleteProfile method deletes a profile.

Quick Info

See IProfAdmin : IUnknown.

HRESULT DeleteProfile(
  LPTSTR lpszProfileName,
  ULONG ulFlags
);

Parameters

lpszProfileName
[in] Pointer to the name of the profile to be deleted.
ulFlags
[in] Bitmask of flags that controls the type of the profile name. The following flag can be set:
MAPI_UNICODE
The profile name is in Unicode format. If the MAPI_UNICODE flag is not set, the profile name is in ANSI format.

Return Values

S_OK
The profile was successfully deleted.
MAPI_E_NOT_FOUND
The specified profile does not exist.

Remarks

The IProfAdmin::DeleteProfile method deletes a profile. If the profile to delete is in use when DeleteProfile is called, DeleteProfile returns S_OK but does not delete the profile immediately. Instead, DeleteProfile marks the profile for deletion and deletes it after it is no longer being used, when all of its active sessions have ended.

The entry point function for each message service in the profile is called with the MSG_SERVICE_DELETE value set in the ulContext parameter. First, the function deletes the service, and then it deletes the service's profile section. The message service entry point function is not called again after the service has been deleted.

No password is required to delete a profile.

See Also

IMsgServiceAdmin::DeleteMsgService, MSGSERVICEENTRY


IProfAdmin::GetLastError

The IProfAdmin::GetLastError method returns a MAPIERROR structure containing information about the previous error occurring to a profile administration object.

Quick Info

See IProfAdmin : IUnknown.

HRESULT GetLastError(
  HRESULT hResult,
  ULONG ulFlags,
  LPMAPIERROR FAR * lppMAPIError
);

Parameters

hResult
[in] HRESULT data type containing the error value generated in the previous method call.
ulFlags
[in] Bitmask of flags that controls the type of the returned strings. The following flag can be set:
MAPI_UNICODE
The strings in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppMAPIError
[out] Pointer to a pointer to the MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Remarks

The IProfAdmin::GetLastError method retrieves information about the last error returned from a method call for the profile administration object.

Notes to Callers

You can make use of the MAPIERROR structure pointed to by the lppMAPIError parameter, if MAPI supplies one, only if GetLastError returns S_OK. Sometimes MAPI cannot determine what the last error was or has nothing more to report about the error. In this situation, a pointer to NULL is returned in lppMAPIError.

To release all the memory allocated by MAPI for the MAPIERROR structure, call the MAPIFreeBuffer function.

For more information about the GetLastError method, see Using Extended Errors.

See Also

MAPIERROR, MAPIFreeBuffer


IProfAdmin::GetProfileTable

The IProfAdmin::GetProfileTable method provides access to the profile table — a table with information about all of the available profiles.

Quick Info

See IProfAdmin : IUnknown.

HRESULT GetProfileTable(
  ULONG ulFlags,
  LPMAPITABLE FAR * lppTable
);

Parameters

ulFlags
[in] Bitmask of flags that controls the type of the strings returned in the table's columns. The following flag can be set:
MAPI_UNICODE
The string columns are in Unicode format. If the MAPI_UNICODE flag is not set, the columns are in ANSI format.
lppTable
[out] Pointer to the pointer to the profile table.

Return Values

S_OK
The profile table was successfully retrieved.

Remarks

The IProfAdmin::GetProfileTable method provides access to the profile table — a table with one row for every available profile. There are only two columns in each row: the profile's display name and a flag that indicates whether or not the profile is the default.

Profiles that have been deleted, or that are in use but have been marked for deletion, are not included in the profile table. The profile table is static; subsequent additions and deletions of profiles are not reflected in the table.

If no profiles exist, GetProfileTable returns a table with zero rows.

Setting the MAPI_UNICODE flag in the ulFlags parameter affects the format of the columns returned from the following IMAPITable methods:

IMAPITable::QueryColumns

IMAPITable::QueryRows

This flag also controls the property types in the sort order returned by the IMAPITable::QuerySortOrder method.

For more information about the profile table, see Profile Table.

See Also

IMAPITable : IUnknown, MAPILogonEx


IProfAdmin::RenameProfile

The IProfAdmin::RenameProfile method assigns a new name to a profile.

Quick Info

See IProfAdmin : IUnknown.

HRESULT RenameProfile(
  LPTSTR lpszOldProfileName,
  LPTSTR lpszOldPassword,
  LPTSTR lpszNewProfileName,
  ULONG ulUIParam,
  ULONG ulFlags
);

Parameters

lpszOldProfileName
[in] Pointer to the current name of the profile to rename.
lpszOldPassword
[in] Pointer to the password of the profile to rename or NULL, indicating that the profile does not require a password. However, if lpszOldPassword is set to NULL and the profile does require a password, RenameProfile displays a dialog box if possible to prompt the user.
lpszNewProfileName
[in] Pointer to the new name of the profile to rename.
ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays.
ulFlags
[in] Bitmask of flags that controls how the renaming operation is performed. The following flags can be set:
MAPI_DIALOG
Allows the display of a dialog box prompting the user for the profile's password. If this flag is not set, no dialog box is displayed.
MAPI_UNICODE
The profile names and password are in Unicode format. If the MAPI_UNICODE flag is not set, these strings are in ANSI format.

Return Values

S_OK
The profile was successfully renamed.
MAPI_E_LOGON_FAILED
The profile password is incorrect.
MAPI_E_USER_CANCEL
The user canceled the operation, typically by clicking the Cancel button in a dialog box.

Remarks

The IProfAdmin::RenameProfile method assigns a new name to a profile without changing its password, if it has one. If the profile to rename is in use by a client when RenameProfile is called, RenameProfile marks the profile and returns S_OK rather than attempting the rename operation while the profile is in use. When the profile is no longer being used, RenameProfile assigns it the new name.

The old and new names of the profile and the password can be up to 64 characters in length and can include the following characters:

  • All alphanumeric characters, including accent characters and the underscore character.
  • Embedded spaces, but not leading or trailing spaces.

Profile passwords are not supported on all operating system platforms; on platforms that do not support profile passwords, lpszPassword can be NULL or a pointer to a zero-length string. Currently, Windows NT Server and Windows 95 do not support passwords; Windows version 3.1 does.

The MAPI_DIALOG flag must be set in order for RenameProfile to display a user interface. If a client passes NULL in lpszOldPassword and the target profile requires a password, a dialog box must be displayed to allow the user to supply the missing password. If MAPI_DIALOG is not set in this situation, RenameProfile returns MAPI_E_LOGON_FAILED.


IProfAdmin::SetDefaultProfile

The IProfAdmin::SetDefaultProfile method sets or clears a client's default profile.

Quick Info

See IProfAdmin : IUnknown.

HRESULT SetDefaultProfile(
  LPTSTR lpszProfileName,
  ULONG ulFlags
);

Parameters

lpszProfileName
[in] Pointer to the name of the profile to become the default, or NULL. Setting lpszProfileName to NULL indicates that SetDefaultProfile should remove the existing default profile, leaving the client without a default.
ulFlags
[in] Bitmask of flags that controls the type of the string pointed to by lpszProfileName. The following flag can be set:
MAPI_UNICODE
The profile name is in Unicode format. If the MAPI_UNICODE flag is not set, the profile name is in ANSI format.

Return Values

S_OK
A default profile was successfully established or removed.
MAPI_E_NOT_FOUND
The specified profile does not exist.

Remarks

The IProfAdmin::SetDefaultProfile method either establishes a particular profile as the client's default profile or clears the current default profile. The default profile is the profile that is automatically used whenever the client begins a MAPI session. SetDefaultProfile also sets the new default profile's PR_DEFAULT_PROFILE property to TRUE.

Notes to Callers

To start a session with the default profile, pass the MAPI_USE_DEFAULT flag to the MAPILogonEx function.

See Also

IProfAdmin::GetProfileTable, MAPILogonEx, PR_DEFAULT_PROFILE


IProfSect : IMAPIProp

The IProfSect interface is used to work with the properties of profile section objects.

Quick Info

Header file: | MAPIX.H
Exposed by: | Profile section objects
Implemented by: | MAPI
Called by: | Client applications and service providers
Interface identifier: | IID_IProfSect
Pointer type: | LPPROFSECT
Transaction model: | Nontransacted

Vtable Order

No unique methods

Required properties | Access
PR_OBJECT_TYPE | Read-only
PR_PROFILE_NAME | Read-only

Notes to Callers

The IProfSect interface does not have any unique methods of its own, but you can call the profile section's IMAPIProp methods. There are some differences between the IProfSect implementation and other implementations of IMAPIProp:

  • IProfSect does not support a transaction model.
  • IProfSect does not support named properties.
  • IProfSect reserves the identifier range 0X67F0 to 0X67FF for secure properties.

Not supporting a transaction model means that all changes made to a profile section following calls to the IMAPIProp::CopyProps and IMAPIProp::CopyTo methods occur immediately. Calls to the IMAPIProp::SaveChanges method succeed, but don't actually save any changes.

To be protected from changes that occur prematurely, service providers need to make copies of their profile sections that are displayed to users through property sheets. The property sheets should work with the copy, rather than the real profile section. When the user has verified that the changes are accurate by clicking the OK button, the changes can be saved to the real profile section.

To implement a property sheet with a copied profile section
  1. Open the profile section by calling IMAPISupport::OpenProfileSection or IProviderAdmin::OpenProfileSection.
  2. Call CreateIProp to retrieve a property data object — an object that supports the IPropData interface.
  3. Call the profile section's IMAPIProp::CopyTo method to copy the properties to appear on the property sheet from the profile section to the property data object.
  4. Call IMAPISupport::DoConfigPropSheet to request that the service provider display a property sheet and pass a pointer to the property data object in the lpConfigData parameter.
  5. When the user saves changes to configuration properties in the property sheet, call the IMAPIProp::CopyTo method to copy the properties from the property data object back to the profile section.

Profile sections, unlike other objects, do not support named properties. IMAPIProp::GetIDsFromNames and IMAPIProp::GetNamesFromIDs return MAPI_E_NO_SUPPORT if called on a profile section object. Attempts to set properties with identifiers in the range above 0x8000 with IMAPIProp::SetProps return PT_ERROR as the property type.

Profile sections reserve the identifier range 0X67F0 to 0X67FF for secure properties. Service providers can use this range to store passwords and other provider-specific credentials. Properties in this range are not returned in the complete list of properties when NULL is passed in the lpPropTag parameter of the IMAPIProp::GetProps method, nor are they returned in the lppPropTagArray parameter of the IMAPIProp::GetPropList method. Secure properties must be requested specifically by their identifiers.

MAPI furnishes a profile section with the hard-coded constant MUID_PROFILE_INSTANCE as its identifier and PR_SEARCH_KEY as its single property. The PR_SEARCH_KEY property is guaranteed by MAPI to be unique among all profiles created. Use this property rather than PR_PROFILE_NAME when uniqueness is important, because it is possible for a deleted profile to be succeeded by another profile with the same name.

For more information on using profile sections, see Administering Profiles and Message Services.


IPropData : IMAPIProp

The IPropData interface provides the ability to retrieve and change the access for an object's properties.

Quick Info

Header file: | MAPIUTIL.H
Exposed by: | Property data object
Implemented by: | MAPI
Called by: | Service providers and client applications
Interface identifier: | IID_IMAPIPropData
Pointer type: | LPPROPDATA
Transaction model: | Nontransacted

Vtable Order

HrSetObjAccess | Sets the access level for the object.
HrSetPropAccess | Sets the access level and status for one or more of the object's properties.
HrGetPropAccess | Retrieves the access level and status for one or more of the object's properties.
HrAddObjProps | Adds one or more properties that are of type PT_OBJECT to the object.

Remarks

The IPropData::IMAPIProp interface is implemented by MAPI and used primarily by service providers that access this implementation by calling the CreateIProp function.

For more information about access levels on objects and properties, see Permissions for Objects and Properties.


IPropData::HrAddObjProps

The IPropData::HrAddObjProps method adds one or more properties that are of type PT_OBJECT to the object.

Quick Info

See IPropData : IMAPIProp.

HRESULT HrAddObjProps(
  LPSPropTagArray lpPropTagArray,
  LPSPropProblemArray FAR * lppProblems
);

Parameters

lpPropTagArray
[in] Pointer to an array of property tags indicating the properties to add.
lppProblems
[in, out] On input, a valid pointer to an SPropProblemArray structure, or NULL. On output, a pointer to a pointer to a structure that holds information about properties that could not be added, or NULL. A pointer to a property problem array structure is returned only if a valid pointer is passed in.

Return Values

S_OK
The properties were successfully added.
MAPI_E_INVALID_TYPE
A property type other than PT_OBJECT was passed in the array pointed to by the lpPropTagArray parameter.
MAPI_E_NO_ACCESS
The object has been set not to allow read/write access.
MAPI_W_PARTIAL_COMPLETION
Some, but not all, of the properties were added.

Remarks

The IPropData::HrAddObjProps method adds one or more properties that are type PT_OBJECT to the object. HrAddObjProps provides an alternative to IMAPIProp::SetProps for object properties because object properties cannot be created by calling SetProps. Adding an object property results in the property tag being included in the list of property tags retrieved through IMAPIProp::GetPropList.

Notes to Callers

If HrAddObjProps returns MAPI_W_PARTIAL_COMPLETION and you have set lppProblems to a valid pointer, check the returned SPropProblemArray structure to find out which properties were not added. Typically, the only problem that occurs is lack of memory. Free the SPropProblemArray structure by calling the MAPIFreeBuffer function when you are finished with it.

To add a property, the target object must have read/write access. If HrAddObjProps returns MAPI_E_NO_ACCESS, this indicates that you cannot add properties to the object because it does not permit modification. To obtain read/write access to an object prior to calling HrAddObjProps, call IPropData::HrSetObjAccess and set the ulAccess parameter to IPROP_READWRITE.

See Also

MAPIFreeBuffer, SPropProblemArray, SPropTagArray


IPropData::HrGetPropAccess

The IPropData::HrGetPropAccess method retrieves the access level and status for one or more of the object's properties.

Quick Info

See IPropData : IMAPIProp.

HRESULT HrGetPropAccess(
  LPSPropTagArray FAR * lppPropTagArray,
  ULONG FAR * FAR * lprgulAccess
);

Parameters

lppPropTagArray
[in, out] On input, contains either an array of property tags indicating the properties for which to retrieve access levels and status or a pointer to NULL, indicating that HrGetPropAccess should retrieve access levels and status for all properties.

On output, contains an array of property tags for which access and status flags were retrieved. The flags are stored in the array pointed to by lprgulAccess.

lprgulAccess
[out] Pointer to an array of bitmasks of flags. Each bitmask indicates the access levels and/or status for each of the properties identified in the array pointed to by lppPropTagArray. The two arrays are positional in that the first bitmask pointed to by lprgulAccess describes the first property pointed to by lppPropTagArray and so on.

For each property tag, the following flags can be set:
Access level flag | Status flag
IPROP_READONLY, indicating that the property cannot be modified | IPROP_CLEAN, indicating that the property has not been modified.
IPROP_READWRITE, indicating that the property can be modified. | IPROP_DIRTY, indicating that the property has been modified.

Return Values

S_OK
The access level and status flags for the properties were successfully returned.

Remarks

The IPropData::HrGetPropAccess method retrieves a set of flags indicating the access level and status for one or more properties.

Notes to Callers:

HrGetPropAccess can be used:

  • To determine if a client has changed or deleted a writable property.
  • To prevent a client from changing or deleting a property using the IMAPIProp methods.

If one of the properties in the property tag array pointed to by lppPropTagArray has been deleted, HrGetPropAccess sets the array entry to zero on output. If you set lppPropTagArray to NULL and one of the object's properties has been deleted, the deleted property is returned in the array.

If a property has been modified, its IPROP_DIRTY flag is set in the corresponding entry in the array pointed to by lprgulAccess. Neither IPROP_READONLY or IPROP_READWRITE will be set.

If a property has not been modified or deleted, only an access level flag will be set: IPROP_READONLY or IPROP_READWRITE.

See Also

SPropTagArray


IPropData::HrSetObjAccess

The IPropData::HrSetObjAccess method sets the access level for the object.

Quick Info

See IPropData : IMAPIProp.

HRESULT HrSetObjAccess(
  ULONG ulAccess
);

Parameters

ulAccess
[in] Bitmask of flags that specifies the object's access level. One of the following flags can be set:
IPROP_READONLY
Sets the object's access level to read-only.
IPROP_READWRITE
Sets the object's access level to read/write.

Return Values

S_OK
The object's access level was successfully set.

Remarks

The IPropData::HrSetObjAccess method sets the access level for an entire object, rather than for individual properties. HrSetObjAccess can be used to change the access level established when the object was created.

Notes to Callers

To set an access level on a property, first call HrSetObjAccess with the IPROP_READWRITE flag set in the ulAccess parameter to make the object modifiable. Then call IPropData::HrSetPropAccess, specifying the target property in the array pointed to by lpPropTagArray.

To create an object with properties that will be read-only to clients, create a read/write object, add the necessary properties, and then call HrSetObjAccess to change the object's access to read-only.

HrSetObjAccess can also be used to prevent clients from creating new properties.

See Also

IPropData::HrGetPropAccess, IPropData::HrSetPropAccess


IPropData::HrSetPropAccess

The IPropData::HrSetPropAccess method sets the access level or status for one or more of the object's properties.

Quick Info

See IPropData : IMAPIProp.

HRESULT HrSetPropAccess(
  LPSPropTagArray lpPropTagArray,
  ULONG FAR * rgulAccess
);

Parameters

lpPropTagArray
[in] Pointer to an array of property tags indicating the properties to be modified.
rgulAccess
[in] Array of bitmasks of flags. Each bitmask indicates the access levels and/or status for each of the properties identified in the array pointed to by lpPropTagArray. The two arrays are positional in that the first bitmask in rgulAccess describes the first property pointed to by lpPropTagArray and so on.

For each property tag, one access level flag and one status flag can be set. Possible flags are:
Access level flag | Status flag
IPROP_READONLY, indicating that the property cannot be modified | IPROP_CLEAN, indicating that the property has not been modified.
IPROP_READWRITE, indicating that the property can be modified. | IPROP_DIRTY, indicating that the property has been modified.

Return Values

S_OK
The access level and status flags have been successfully set.
MAPI_E_NO_ACCESS
An attempt was made to set a property on a read-only object or an object for which the caller has insufficient permissions.
MAPI_E_INVALID_PARAMETER
The rgulAccess parameter contains an invalid combination of flags, such as IPROP_READONLY and IPROP_READWRITE.

Remarks

The IPropData::HrSetPropAccess method changes the access level and status for the properties that are identified by the property tags in the SPropTagArray structure pointed to by lpPropTagArray. For each property, there is a corresponding entry in the rgulAccess array. The entry can be set to one flag that indicates the property's access level and another flag that indicates its status.

Notes to Callers

Use HrSetPropAccess for determining when a particular property value changes and to change the access level for one or more of an object's properties.

See Also

SPropTagArray


IProviderAdmin : IUnknown

The IProviderAdmin interface is used to work with service providers within a message service.

Quick Info

Header file: | MAPIDEFS.H
Exposed by: | Provider administration objects
Implemented by: | MAPI
Called by: | Client applications and service providers
Interface identifier: | IID_IProviderAdmin
Pointer type: | LPPROVIDERADMIN

Vtable Order

GetLastError | Returns a MAPIERROR structure containing information about the previous error occurring to the provider administration object.
GetProviderTable | Provides access to the message service's provider table — a listing of the service providers in the message service.
CreateProvider | Adds a service provider to the message service.
DeleteProvider | Deletes a service provider from the message service.
OpenProfileSection | Opens a profile section from the current profile and returns an IProfSect pointer for further access.

Remarks

Clients can get a pointer to an IProviderAdmin interface by calling IMsgServiceAdmin::AdminProviders; service providers are passed an IProviderAdmin pointer when their message service's entry point function is called.


IProviderAdmin::CreateProvider

The IProviderAdmin::CreateProvider method adds a service provider to the message service.

Quick Info

See IProviderAdmin : IUnknown.

HRESULT CreateProvider(
  LPTSTR lpszProvider,
  ULONG cValues,
  LPSPropValue lpProps,
  ULONG ulUIParam,
  ULONG ulFlags,
  MAPIUID FAR * lpUID
);

Parameters

lpszProvider
[in] Pointer to the name of the provider to add.
cValues
[in] Count of property values pointed to by the lpProps parameter.
lpProps
[in] Pointer to an property value array describing the properties of the provider to add.
ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays. The ulUIParam parameter is used if the MAPI_DIALOG flag is set in the ulFlags parameter.
ulFlags
[in] Bitmask of flags that controls the provider addition. The following flags can be set:
MAPI_DIALOG
Allows the display of a dialog box to prompt for configuration information.
MAPI_UNICODE
The provider name and string properties are in Unicode format. If the MAPI_UNICODE flag is not set, these strings are in ANSI format.
lpUID
[out] Pointer to the MAPIUID structure holding the unique identifier representing the provider to add.

Return Values

S_OK
The provider was successfully added to the message service.
MAPI_E_USER_CANCEL
The user canceled the operation, typically by clicking the Cancel button in a dialog box.

Remarks

The IProviderAdmin::CreateProvider method adds a service provider to the message service. The lpszProvider parameter must point to the name of a provider that belongs to the message service. CreateProvider does not verify that the name matches the name of a provider in the service; if the passed name doesn't match a service name, the call succeeds, but the results are unpredictable. Most message services do not allow providers to be added or deleted while the profile is in use.

After all of the available information about the service provider has been added to the profile from the MAPISVC.INF file, CreateProvider calls the message service's entry point function with the ulContext parameter set to MSG_SERVICE_PROVIDER_CREATE. If MAPI_DIALOG is set in the CreateProvider method's ulFlags parameter, then the values in the ulUIParam and ulFlags parameters are also passed to the entry point function. These additional parameters allow the service provider to display its property sheet so that the user can enter configuration settings.

See Also

MAPIUID, MSGSERVICEENTRY, SPropValue


IProviderAdmin::DeleteProvider

The IProviderAdmin::DeleteProvider method deletes a service provider from the message service.

Quick Info

See IProviderAdmin : IUnknown.

HRESULT DeleteProvider(
  LPMAPIUID lpUID
);

Parameters

lpUID
[in] [out] Pointer to the MAPIUID structure holding the unique identifier representing the provider to delete.

Return Values

S_OK
The provider was successfully deleted from the message service.
MAPI_E_NOT_FOUND
The MAPIUID pointed to by the lpUID parameter was not recognized.

Remarks

The IProviderAdmin::DeleteProvider method deletes a service provider from the message service. DeleteProvider determines the service provider to delete by matching the MAPIUID structure pointed to by lpUID with the set of identifiers registered by the active service providers.

Most message services do not allow providers to be deleted while the profile is in use. If the provider to delete is in use, DeleteProvider marks it for deletion instead of removing it immediately and returns S_OK. When the provider is no longer being used, it is deleted.

DeleteProvider calls the message service's entry point function before the provider is removed from the service. The ulContext parameter is set to MSG_SERVICE_PROVIDER_DELETE. The message service entry point function performs the following tasks:

  • Deletes the service provider.
  • Deletes the service provider's profile section.

The message service entry point function is not called again after the provider has been deleted.

See Also

MAPIUID, MSGSERVICEENTRY


IProviderAdmin::GetLastError

The IProviderAdmin::GetLastError method returns a MAPIERROR structure containing information about the previous error occurring to the provider administration object.

Quick Info

See IProviderAdmin : IUnknown.

HRESULT GetLastError(
  HRESULT hResult,
  ULONG ulFlags,
  LPMAPIERROR FAR * lppMAPIError
);

Parameters

hResult
[in] HRESULT data type containing the error value generated in the previous method call.
ulFlags
[in] Bitmask of flags that controls the type of the returned strings. The following flag can be set:
MAPI_UNICODE
The strings in the MAPIERROR structure returned in the lppMAPIError parameter are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppMAPIError
[out] Pointer to a pointer to the returned MAPIERROR structure containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and GetLastError does not support Unicode, or MAPI_UNICODE was not set and GetLastError only supports Unicode.

Remarks

The IProviderAdmin::GetLastError method supplies information about a prior method call that failed. Callers can provide their users with detailed information about the error by including the data from the MAPIERROR structure in a dialog box.

Notes to Callers

You can make use of the MAPIERROR structure pointed to by the lppMAPIError parameter — if MAPI supplies one — only if GetLastError returns S_OK. Sometimes MAPI cannot determine what the last error was or has nothing more to report about the error. In this situation, a pointer to NULL is returned in lppMAPIError instead.

For more information about the GetLastError method, see Using Extended Errors.

See Also

MAPIERROR, MAPIFreeBuffer


IProviderAdmin::GetProviderTable

The IProviderAdmin::GetProviderTable method provides access to the message service's provider table — a listing of the service providers in the message service.

Quick Info

See IProviderAdmin : IUnknown.

HRESULT GetProviderTable(
  ULONG ulFlags,
  LPMAPITABLE FAR * lppTable
);

Parameters

ulFlags
[in] Bitmask of flags that controls the type of the strings returned in the provider table's columns. The following flag can be set:
MAPI_UNICODE
The string columns are in Unicode format. If the MAPI_UNICODE flag is not set, the columns are in ANSI format.
lppTable
[out] Pointer to a pointer to the provider table.

Return Values

S_OK
The provider table was successfully returned.

Remarks

The IProviderAdmin::GetProviderTable method retrieves a pointer to the message service's provider table — a table maintained by MAPI that contains information about each service provider in the message service.

Unlike the provider table returned through IMsgServiceAdmin::GetProviderTable, the provider table returned through IProviderAdmin::GetProviderTable may include additional rows that represent information associated with one or more of the service providers in the message service. This extra information is added to the profile with the "Sections" keyword of MAPISVC.INF. When a provider has extra profile sections, it stores the MAPIUIDs for these sections in the PR_SERVICE_EXTRA_UIDS property. PR_SERVICE_EXTRA_UIDS is saved in the message service profile section.

Providers that have been deleted, or are in use but have been marked for deletion, are not included in the provider table. Provider tables are static, meaning that subsequent additions to or deletions from the message service are not reflected in the table.

If the message service has no providers, GetProviderTable returns a table with zero rows and the S_OK return value.

Setting the MAPI_UNICODE flag in the ulFlags parameter affects the format of the columns returned from the following IMAPITable methods:

IMAPITable::QueryColumns

IMAPITable::QueryRows

This flag also controls the property types in the sort order returned by the IMAPITable::QuerySortOrder method.

For a complete list of the columns in the provider table, see Provider Table.

Notes to Callers

To retrieve the rows of a provider table in transport order, sort the table by the PR_PROVIDER_ORDINAL column.

To retrieve only those rows that represent service providers without including any extra rows, limit your retrieval to the rows that do have a value of PT_ERROR in their PR_RESOURCE_TYPE column.

See Also

IMAPITable::QueryColumns, IMAPITable::QueryRows, IMAPITable::QuerySortOrder, IMAPITable::SetColumns, IMsgServiceAdmin::GetProviderTable


IProviderAdmin::OpenProfileSection

The IProviderAdmin::OpenProfileSection method opens a profile section from the current profile and returns an IProfSect pointer for further access.

Quick Info

See IProviderAdmin : IUnknown.

HRESULT OpenProfileSection(
  LPMAPIUID lpUID,
  LPCIID lpInterface,
  ULONG ulFlags,
  LPPROFSECT FAR * lppProfSect
);

Parameters

lpUID
[in] Pointer to the MAPIUID structure holding the unique identifier for the profile section to be opened. Clients must not pass NULL for the lpUID parameter. Service providers can pass NULL to retrieve the MAPIUID when calling from their message service entry point functions.
lpInterface
[in] Pointer to the interface identifier (IID) representing the interface to be used to access the profile section. Passing NULL results in the profile section's standard interface, or IProfSect, being returned.
ulFlags
[in] Bitmask of flags that controls how the profile section is opened. The following flags can be set:
MAPI_DEFERRED_ERRORS
Allows OpenProfileSection to return successfully, possibly before the profile section is fully accessible to the caller. If the profile section is not accessible, making a subsequent call to it can result in an error.
MAPI_MODIFY
Requests read/write access. By default, objects are opened with read-only access, and callers should not work on the assumption that read/write access has been granted. Clients are not allowed read/write access to provider sections of the profile.
lppProfSect
[out] Pointer to a pointer to the profile section.

Return Values

S_OK
The profile section was successfully opened.
MAPI_E_NO_ACCESS
An attempt was made to modify a read-only profile section or to access an object for which the user has insufficient permissions.
MAPI_E_NOT_FOUND
The requested profile section does not exist.

Remarks

The IProviderAdmin::OpenProfileSection method opens a profile section, allowing the caller to read information from and possibly write information to the active profile.

Clients cannot open profile sections belonging to providers using the IProviderAdmin::OpenProfileSection method.

Multiple clients or service providers can simultaneously open a profile section with read-only access. However, when a profile section is open with read/write access, no other calls can be made to open the section, regardless of the type of access. If a profile section is open with read-only access, a subsequent call to request read/write access will fail with MAPI_E_NO_ACCESS. Likewise, if a section is open with read/write access, a subsequent call to request read-only access will also fail.

Notes to Callers

If you request that OpenProfileSection open a nonexistent profile section by passing MAPI_MODIFY in ulFlags and an unknown MAPIUID in lpUID, the profile section will be created.

If you request that OpenProfileSection open a nonexistent section with read-only access, it returns MAPI_E_NOT_FOUND.

See Also

IMAPIProp : IUnknown, IProfSect : IMAPIProp, MAPIUID


ISpoolerHook : IUnknown

The ISpoolerHook interface enables a messaging hook provider to process messages before they go to their destination. This processing can include modifying the message, changing the list of recipients, saving a copy of the message elsewhere, and so on.

Quick Info

Header file: | MAPIHOOK.H
Exposed by: | Messaging hook provider objects
Implemented by: | Messaging hook providers
Called by: | MAPI spooler
Interface identifier: | IID_ISpoolerHook
Pointer type: | LPSPOOLERHOOK

Vtable Order

InboundMsgHook | Called by the MAPI spooler. The method can perform arbitrary processing on an inbound message and can change the message's delivery point from the Inbox to another folder..
OutboundMsgHook | Called by the MAPI spooler to process outgoing messages. This processing can include archiving the message in a Sent Items folder, modifying the message, and so on.


ISpoolerHook::InboundMsgHook

The ISpoolerHook::InboundMsgHook method is called by the MAPI spooler. The method can perform arbitrary processing on an inbound message and can change the message's delivery point from the Inbox to another folder.

Quick Info

See ISpoolerHook : IUnknown.

HRESULT InboundMsgHook(
  LPMESSAGE lpMessage,
  LPMAPIFOLDER lpFolder,
  LPMDB lpMDB,
  ULONG FAR * lpulFlags,
  ULONG FAR * lpcbEntryID,
  LPBYTE FAR * lppEntryID
);

Parameters

lpMessage
[in] Pointer to the message to process.
lpFolder
[in] Pointer to the parent folder of the message in its message store.
lpMDB
[in] Pointer to the message store containing the folder and message.
lpulFlags
[out] Bitmask of flags that controls how the MAPI spooler responds to the hook for the message indicated in the lpMessage parameter. The following flags can be set:
HOOK_CANCEL
Any subsequent hook functions should not be called for this message. If a hook closes, moves, or deletes the message, the messaging hook provider should set this flag.
HOOK_DELETE
The message should be deleted without being moved.
lpcbEntryID
[in, out] Pointer to the size, in bytes, of the entry identifier pointed to by the lppEntryID parameter.
lppEntryID
[in, out] Pointer to the pointer to the entry identifier of the destination folder, if the hook processor moves the message. This can be NULL if the hook does not move the message.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Notes to Implementers

Messaging hook providers implement the ISpoolerHook::InboundMsgHook method to process inbound messages. This processing can include rerouting a message from the default Inbox to another folder, modifying the message, or automatically deleting it. Before processing a message, a messaging hook provider should call the IUnknown::QueryInterface method for the message object to make sure the provider can get an interface for the message that is compatible with the provider's implementation.

To modify a message, the hook processor must change the values of the message's properties. For example, if a hook processor is created to make message delivery information explicit in the body of the message, it must take information from the message's header properties and insert it somewhere in the message's PR_BODY or PR_RTF_COMPRESSED properties. The hook processor should call the IMAPIProp::SaveChanges method after modifying the message's properties.

To reroute a message, a messaging hook provider must replace the passed-in entry identifier in lppEntryID with the entry identifier of the new target folder. The MAPI spooler moves the message to the indicated folder for the provider, unless another hook function replaces the folder entry identifier again. If a hook requires that its operation be the final action on the message, it can set the HOOK_CANCEL flag in the lpulFlags parameter before returning.

If a provider replaces the lppEntryID entry identifier, it must call the MAPIFreeBuffer function to free the original one. The entry identifier the provider stores in lppEntryID should be allocated using the MAPIAllocateBuffer function.

If a messaging hook must move a message to another folder itself rather than letting the MAPI spooler move the message, it should close the message, place zero in the lpcbEntryID parameter, and free the lppEntryID entry identifier, if lppEntryID is not already NULL. The hook then sets lppEntryID to NULL and places a pointer to the message's new parent folder in lpFolder. Messaging hook providers that move the message must set HOOK_CANCEL in lpulFlags.

If a hook needs to delete a message, it only needs to set both the HOOK_CANCEL and HOOK_DELETE flags in lpulFlags. The MAPI spooler will take care of deleting the message from the message store.

The MAPI spooler calls hook providers in the order in which they are specified in the provider section of the profile, as it does transport providers. The MAPI spooler releases the messaging hook provider object at session shutdown. If a hook provider calls the IUnknown::AddRef method for a session at initialization, at shutdown it should call the IUnknown::Release method to release the session and any objects, such as message stores, it opened and maintained during the session.


ISpoolerHook::OutboundMsgHook

The ISpoolerHook::OutboundMsgHook method is called by the MAPI spooler to process outgoing messages. This processing can include archiving the message in a Sent Items folder, modifying the message, and so on.

Quick Info

See ISpoolerHook : IUnknown.

HRESULT OutboundMsgHook(
  LPMESSAGE lpMessage,
  LPMAPIFOLDER lpFolder,
  LPMDB lpMDB,
  ULONG FAR * lpulFlags,
  ULONG FAR * lpcbEntryID,
  LPBYTE FAR * lppEntryID
);

Parameters

lpMessage
[in] Pointer to the message to process.
lpFolder
[in] Pointer to the parent folder of the message in its message store.
lpMDB
[in] Pointer to the message store containing the folder and message.
lpulFlags
[out] Bitmask of flags that controls how the MAPI spooler responds to the hook for the message indicated in the lpMessage parameter. The following flags can be set:
HOOK_CANCEL
Any subsequent hook functions should not be called for this message. If a hook closes, moves, or deletes the message, the messaging hook provider should set this flag.
HOOK_DELETE
The message should be deleted without being moved.
lpcbEntryID
[in, out] Pointer to the size, in bytes, of the entry identifier pointed to by the lppEntryID parameter.
lppEntryID
[in, out] Pointer to the pointer to the entry identifier of the destination folder, if the hook processor moves the message. This can be NULL if the hook does not move the message.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

The ISpoolerHook::OutboundMsgHook method is called after the message has been submitted to any transport providers. To process an outgoing message before the message is sent, use a preprocessor. See About Preprocessors for details.

Notes to Implementers

Messaging hook providers implement the ISpoolerHook::OutboundMsgHook method to process outbound messages. Because outbound message hooks are called after a message has been sent, they are typically used to save sent messages to one or more Sent Items folders. Before processing a message, a messaging hook provider should call the IUnknown::QueryInterface method for the message object to make sure the provider can get an interface for the message that is compatible with the provider's implementation.

To move a message, a messaging hook provider must replace the passed-in entry identifier in lppEntryID with the entry identifier of the new target folder. The MAPI spooler saves the message to the indicated folder for the provider, unless another hook function replaces the folder entry identifier. If a hook requires that its operation be the final action on the message, it can set the HOOK_CANCEL flag in the lpulFlags parameter before returning.

If a provider replaces the lppEntryID entry identifier, it must call the MAPIFreeBuffer function to free the previous one. The entry identifier the provider stores in lppEntryID should be allocated using the MAPIAllocateBuffer function.

If a messaging hook provider's implementation must move a message to another folder itself instead of allowing the MAPI spooler to move the message, it should close the message, place zero in the lpcbEntryID parameter, and free the lppEntryID entry identifier if it is not already NULL. The hook then sets lppEntryID to NULL and places a pointer to the message's new parent folder in lpFolder. Messaging hook providers that move the message must set HOOK_CANCEL in lpulFlags.

If a hook needs to delete a message, it sets the HOOK_CANCEL and HOOK_DELETE flags in lpulFlags. The MAPI spooler then deletes the message from its message store.

The MAPI spooler calls hook providers in the order in which they are specified in the provider section of the profile, as it does transport providers. The MAPI spooler releases the messaging hook provider object at session shutdown. If a provider called the IUnknown::AddRef method for a session at initialization, it should call the IUnknown::Release method to release the session and any objects, such as message stores, it opened and maintained during the session.


ITableData : IUnknown

The ITableData interface provides utility methods for working with tables. Table data objects — or objects that implement ITableData — are provided by MAPI to help service providers perform table maintenance. To obtain a table data object, service providers call the CreateTable function.

Quick Info

Header file: | MAPIUTIL.H
Exposed by: | Table data objects
Implemented by: | MAPI
Called by: | Service providers
Interface identifier: | IID_IMAPITableData
Pointer type: | LPTABLEDATA

Vtable Order

HrGetView | Creates a table view, returning a pointer to an IMAPITable implementation.
HrModifyRow | Inserts a new table row, possibly replacing an existing row.
HrDeleteRow | Deletes a table row.
HrQueryRow | Retrieves a table row.
HrEnumRow | Retrieves a row based on its position in the table.
HrNotify | Sends a notification for a table row.
HrInsertRow | Inserts a table row.
HrModifyRows | Inserts multiple table rows, possibly replacing existing rows.
HrDeleteRows | Deletes multiple table rows.

Remarks

The MAPI implementation of ITableData works with tables by holding all of the data and any associated restrictions in memory, making it unsuitable for use with very large tables. Large restrictions and complex operations such as categorization are unsupported.

Table data objects identify rows using an index column — a property that is guaranteed to have a unique value for each row. Most service providers use the PR_INSTANCE_KEY property as the index column. Multivalued properties cannot be used as an index column.

Table data objects generate a single notification regardless of the number of rows affected by a change or deletion. If a target row in an operation does not exist, a row is added.


ITableData::HrDeleteRow

The ITableData::HrDeleteRow method deletes a table row.

Quick Info

See ITableData : IUnknown.

HRESULT HrDeleteRow(
  LPSPropValue lpSPropValue
);

Parameters

lpSPropValue
[in] Pointer to a property value structure describing the index column for the row to be deleted. The ulPropTag member of the property value structure should contain the same property tag as the ulPropTagIndexColumn parameter from the call to CreateTable.

Return Values

S_OK
The row was successfully deleted.
MAPI_E_NOT_FOUND
The property pointed to by the lpSPropValue parameter does not identify a row in the table.

Remarks

The ITableData::HrDeleteRow method removes the table row containing the column that matches the property pointed to by the lpSPropValue parameter. The data for the row is deleted and the row is removed from all open views.

After the row is deleted, notifications are sent to all clients or service providers with a view of the table that have called the table's IMAPITable::Advise method to register for notifications.

Deleting a row does not reduce the column set available to existing views or subsequently opened views, even if the deleted row was the last row with a value for a specific column.

See Also

CreateTable, ITableData::HrDeleteRows, ITableData::HrModifyRow, SPropValue, TABLE_NOTIFICATION


ITableData::HrDeleteRows

The ITableData::HrDeleteRows method deletes multiple table rows.

Quick Info

See ITableData : IUnknown.

HRESULT HrDeleteRows(
  ULONG ulFlags,
  LPSRowSet lprowsetToDelete,
  ULONG FAR * cRowsDeleted
);

Parameters

ulFlags
[in] Bitmask of flags that controls the deletion. The following flag can be set:
TAD_ALL_ROWS
Deletes all rows from the table and all corresponding views, sending a single TABLE_RELOAD notification.
lprowsetToDelete
[in] Pointer to a row set describing the rows to be deleted. The lprowsetToDelete parameter can be NULL if the TAD_ALL_ROWS flag is set in the ulFlags parameter.
cRowsDeleted
[out] Count of the deleted rows.

Return Values

S_OK
The table rows were successfully deleted.

Remarks

The ITableData::HrDeleteRows method locates and removes the table rows containing the columns that match the property pointed to by the lpProps member of each aRow entry in the row set. An index column is used to identify each row; this column must have the same property tag as the property tag passed in the ulPropTagIndexColumn parameter in the call to CreateTable.

The number of rows that were actually deleted is returned in cRowsDeleted. No error is returned if one or more rows could not be found.

After the rows are deleted, notifications are sent to all clients or service providers with a view of the table and that have called the table's IMAPITable::Advise method to register for notifications.

Deleting rows does not reduce the columns available to existing table views or subsequently opened table views, even if the rows deleted were the last with values for a specific column.

See Also

CreateTable, ITableData::HrDeleteRow, ITableData::HrModifyRows, SRowSet, TABLE_NOTIFICATION


ITableData::HrEnumRow

The ITableData::HrEnumRow method retrieves a row based on its position in the table.

Quick Info

See ITableData : IUnknown.

HRESULT HrEnumRow(
  ULONG ulRowNumber,
  LPSRow FAR * lppSRow
);

Parameters

ulRowNumber
[in] Number of the row for which to return properties. The value in the ulRowNumber parameter can be any value from 0, indicating the first row in the table, through n – 1, indicating the last row in the table.
lppSRow
[out] Pointer to a pointer to an SRow structure describing the target row.

Return Values

S_OK
The row was retrieved successfully or a row for the row number specified by the ulRowNumber parameter does not exist.

Remarks

The ITableData::HrEnumRow method retrieves a row based on a sequential number. This number represents the order of insertion, with 0 being the first row and the number of rows minus 1 being the last row. MAPI maintains this chronological order of row insertion for the lifetime of the table data object.

If the number specified in ulRowNumber does not correspond to a row in the table, HrEnumRow returns S_OK and sets the lppSRow parameter to NULL.

MAPI allocates memory for the returned SRow structure using the MAPIAllocateBuffer function when the table data object is created. The caller must release this memory by calling the MAPIFreeBuffer function.

To retrieve rows from a table in the order that they were inserted, table data object users call the HrEnumRow method.

See Also

MAPIAllocateBuffer, MAPIFreeBuffer, SRow


ITableData::HrGetView

The ITableData::HrGetView method creates a table view, returning a pointer to an IMAPITable implementation.

Quick Info

See ITableData : IUnknown.

HRESULT HrGetView(
  LPSSortOrderSet lpSSortOrderSet,
  CALLERRELEASE FAR * lpfCallerRelease,
  ULONG ulCallerData,
  LPMAPITABLE FAR * lppMAPITable
);

Parameters

lpSSortOrderSet
[in] Pointer to a sort order structure describing the sort order for the table view. If NULL is passed in the lpSSortOrderSet parameter, the view is not sorted.
lpfCallerRelease
[in] Pointer to a callback function based on the CALLERRELEASE prototype that MAPI calls when it releases the view. If NULL is passed in the lpfCallerRelease parameter, no function is called upon release of the view.
ulCallerData
[in] Data that must be saved with the new view and passed to the callback function pointed to by lpfCallerRelease.
lppMAPITable
[out] Pointer to a pointer to the newly created view.

Return Values

S_OK
The view was successfully created.

Remarks

The ITableData::HrGetView method creates a read-only view of the data in the table sorted in the order pointed to by lpSSortOrderSet. The cursor is placed at the beginning of the first row in the view. An IMAPITable interface implementation for accessing the view is returned.

Service providers call HrGetView when they need to give a client access to a table. HrGetView creates the view and returns the IMAPITable pointer. Service providers in turn pass the pointer on to the client. When the client is finished using the table and calls its IUnknown::Release method, HrGetView calls the callback function pointed to by the lpfCallerRelease parameter.

If a service provider needs to return to a client a view that has a customized column set or a restriction in place, the provider can call the view's IMAPITable::SetColumns and Restrict methods before allowing the client access.

See Also

CALLERRELEASE, IMAPITable : IUnknown, SSortOrderSet


ITableData::HrInsertRow

The ITableData::HrInsertRow method inserts a table row.

Quick Info

See ITableData : IUnknown.

HRESULT HrInsertRow(
  ULONG uliRow,
  LPSRow lpSRow
);

Parameters

uliRow
[in] A sequential row number representing the row after which the new row should be inserted. The uliRow parameter can hold row numbers from 0 through n, where n is the total number of rows in the table; passing n in uliRow results in the row being appended to the table's end.
lpSRow
[in] Pointer to an SRow structure describing the row to be inserted.

Return Values

S_OK
The row was successfully inserted.
MAPI_E_INVALID_PARAMETER
A row already exists in the table with the same value for its index column as the row to be inserted.

Remarks

The ITableData::HrInsertRow method inserts a row into a table at a particular position. The new row is inserted after the row that is in the position specified by the uliRow parameter.

If uliRow is set to the number of rows in the table, the new row is appended to the table's end.

The property that acts as the index column for the table must be included in the lpProps member of the SRow structure pointed to by the lpSRow parameter. This index property, typically PR_INSTANCE_KEY, is used to uniquely identify the row for future maintenance tasks.

The property columns in the SRow structure do not have to be in the same order as the property columns in the table.

After the row is inserted, notifications are sent to all clients or service providers with a view of the table that have called the table's IMAPITable::Advise method to register for notifications. No notification is sent if the inserted row is not included in the view due to a restriction.

See Also

SRow, TABLE_NOTIFICATION


ITableData::HrModifyRow

The ITableData::HrModifyRow method inserts a new table row, possibly replacing an existing row.

Quick Info

See ITableData : IUnknown.

HRESULT HrModifyRow(
  LPSRow lpSRow
);

Parameters

lpSRow
[in] Pointer to an SRow structure describing the row to be added or to replace an existing row. One of the property value structures pointed to by the lpProps member of the SRow structure should contain the index column, the same property that was specified in the ulPropTagIndexColumn parameter in the call to CreateTable.

Return Values

S_OK
The row was successfully inserted or modified.
MAPI_E_INVALID_PARAMETER
The passed-in row does not have an index column.

Remarks

The ITableData::HrModifyRow method inserts the row described by the SRow structure pointed to by the lpSRow parameter. If a row already exists in the table that has the same value for its index column as the row that is pointed to by lpSRow, the existing row is replaced. If no row exists that matches the one included in the SRow structure, HrModifyRow adds the row to the end of the table.

All views of the table are modified to include the row pointed to by lpSRow. However, if a view has a restriction in place that excludes the row, it may not be visible to the user.

The columns in the row pointed to by lpSRow do not have to be in the same order as the columns in the table. The caller can also include as columns properties that are not currently in the table. For existing views, HrModifyRow makes these new columns available but does not include them in the current column set. For future views, HrModifyRow includes the new columns in the column set.

After HrModifyRow has added the row, notifications are sent to all clients or service providers with a view of the table and that have called the table's IMAPITable::Advise method to register for notifications.

See Also

SRow, TABLE_NOTIFICATION


ITableData::HrModifyRows

The ITableData::HrModifyRows method inserts multiple table rows, possibly replacing existing rows.

Quick Info

See ITableData : IUnknown.

HRESULT HrModifyRows(
  ULONG ulFlags,
  LPSRowSet lpSRowSet
);

Parameters

ulFlags
Reserved; must be zero.
lpSRowSet
[in] Pointer to an SRowSet structure containing the set of rows to be added, replacing existing rows if necessary. One of the property value structures pointed to by the lpProps member of each SRow structure in the row set should contain the index column — the same property that was specified in the ulPropTagIndexColumn parameter in the call to CreateTable.

Return Values

S_OK
The rows were successfully inserted or modified.
MAPI_E_INVALID_PARAMETER
One or more of the passed-in rows does not have an index column. If this error is returned, no rows are changed.

Remarks

The ITableData::HrModifyRows method inserts the rows described by the SRowSet structure pointed to by the lpSRowSet parameter. For each row in the row set, if its index column value matches the value for an existing row in the table, the existing row is replaced. If no row exists that matches the one included in the SRowSet structure, HrModifyRows adds the row to the end of the table.

All views of the table are modified to include the rows pointed to by lpSRowSet. However, if a view has a restriction in place that excludes a row, it may not be visible to the user.

The columns in the rows pointed to by lpSRowSet do not have to be in the same order as the columns in the table. The caller can also include as columns properties that are not currently in the table. For existing views, HrModifyRows makes these new columns available but does not include them in the current column set. For future views, HrModifyRows includes the new columns in the column set.

After HrModifyRows has added the rows, notifications are sent to all clients or service providers with a view of the table and that have called the table's IMAPITable::Advise method to register for notifications. MAPI sends TABLE_ROW_ADDED or TABLE_ROW_MODIFIED notifications for each row for up to eight rows. If more than eight rows are affected by the HrModifyRows call, MAPI sends a single TABLE_CHANGED notification instead.

See Also

SRowSet


ITableData::HrNotify

The ITableData::HrNotify method sends a notification for a table row.

Quick Info

See ITableData : IUnknown.

HRESULT HrNotify(
  ULONG ulFlags,
  ULONG cValues,
  LPSPropValue lpSPropValue
);

Parameters

ulFlags
Reserved; must be zero.
cValues
[in] Count of property values in the SPropValue structure pointed to by the lpSPropValue parameter.
lpSPropValue
[in] Pointer to an SPropValue structure describing the values of the columns in the target row.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

The ITableData::HrNotify method sends a TABLE_ROW_MODIFIED notification for the row that matches the row described by the properties pointed to by the lpSPropValue parameter. HrNotify sends the notification regardless of whether changes have occurred to the row. All clients and service providers that hold views of the table and have called IMAPITable::Advise to register for notifications on their views receive this notification.

See Also

SPropValue, TABLE_NOTIFICATION


ITableData::HrQueryRow

The ITableData::HrQueryRow method retrieves a table row.

Quick Info

See ITableData : IUnknown.

HRESULT HrQueryRow(
  LPSPropValue lpSPropValue,
  LPSRow FAR * lppSRow,
  ULONG FAR * lpuliRow
);

Parameters

lpSPropValue
[in] Pointer to a property value structure describing the index column for the row to be retrieved. The ulPropTag member of the property value structure should contain the same property tag as the ulPropTagIndexColumn parameter from the call to CreateTable — the function used to access the ITableData implementation.
lppSRow
[out] Pointer to a pointer to the retrieved row.
lpuliRow
[in, out] On input, either a valid pointer or NULL, indicating no information need be returned. On output, a valid pointer points to the row's row number, a sequential number that identifies the row's position in the table.

Return Values

S_OK
The row was successfully retrieved.
MAPI_E_INVALID_PARAMETER
The SPropValue structure pointed to by lpSPropValue does not contain the index column property.

Remarks

The ITableData::HrQueryRow method retrieves all of the properties for the row that has an index column that matches the value of the index column included in the property structure pointed to by lpSPropValue. HrQueryRow also returns, if desired by the caller, the row number identifying the row's position within the table.

Because HrQueryRow does not modify the SPropValue structure pointed to by lpSPropValue, callers must free it when HrQueryRow returns. Callers must also free the SRow structure containing the retrieved row.

See Also

MAPIAllocateBuffer, MAPIFreeBuffer, SPropValue, SRow


ITnef : IUnknown

The ITnef interface provides methods for encapsulating those MAPI properties not supported by a messaging system into binary streams that can be attached to messages. The format used for this encapsulation is Transport-Neutral Encapsulation Format (TNEF). The target transport provider or MAPI-based client application can then, on receiving a message including a TNEF attachment, recover the properties from the attachment.

Quick Info

Header file: | TNEF.H
Exposed by: | TNEF objects
Implemented by: | MAPI
Called by: | Transport providers, message store providers, gateways
Interface identifier: | IID_ITNEF
Pointer type: | LPTNEF

Vtable Order

AddProps | Allows the calling service provider or gateway to add properties to the TNEF encapsulation.
ExtractProps | Extracts the properties from a TNEF encapsulation.
Finish | Finishes processing for all TNEF operations that are queued and waiting.
OpenTaggedBody | Opens a stream interface on the text of an encapsulated message.
SetProps | Sets the value of one or more properties for an encapsulated message or attachment without modifying the original message or attachment.
EncodeRecips | Encodes a message's recipient table into the TNEF data stream for the message.
FinishComponent | Processes individual components from a message one at a time into a TNEF stream.


ITnef::AddProps

The ITnef::AddProps method allows the calling service provider or gateway to add properties to the encapsulation of a message or an attachment.

Quick Info

See ITnef : IUnknown.

HRESULT AddProps(
  ULONG ulFlags,
  ULONG ulElemID,
  LPVOID lpvData,
  LPSPropTagArray lpPropList
);

Parameters

ulFlags
[in] Bitmask of flags that controls how properties are included in or excluded from encapsulation. The following flags can be set:
TNEF_PROP_ATTACHMENTS_ONLY
Encodes only the properties in the lpPropList parameter that are part of attachments within the message.
TNEF_PROP_CONTAINED
Encodes only properties from the attachment specified by the ulElemID parameter. If the lpvData parameter is non-null, the data pointed to is written into the attachment's encapsulation in the file indicated by the PR_ATTACH_TRANSPORT_NAME property.
TNEF_PROP_CONTAINED_TNEF
Encodes only properties from the message or attachment specified by ulElemID. If this flag is set, the value in lpvData must be an ISTREAMTNEF pointer.
TNEF_PROP_EXCLUDE
Encodes all properties not specified in lpPropList.
TNEF_PROP_INCLUDE
Encodes all properties specified in lpPropList.
TNEF_PROP_MESSAGE_ONLY
Encodes only those properties specified in lpPropList that are part of the message itself.
ulElemID
[in] An attachment's PR_ATTACH_NUM property, which holds a number that uniquely identifies the attachment within its parent message. The ulElemID parameter is used when special handling is requested for an attachment. The ulElemID parameter should be zero unless the TNEF_PROP_CONTAINED or TNEF_PROP_CONTAINED_TNEF flag is set in the ulFlags parameter.
lpvData
[in] Pointer to attachment data used to replace the data of the attachment specified in ulElemID. The lpvData parameter should be NULL unless TNEF_PROP_CONTAINED or TNEF_PROP_CONTAINED_TNEF is set in ulFlags.
lpPropList
[in] Pointer to the list of properties to include in or exclude from encapsulation.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Transport providers, message store providers, and gateways call the ITnef::AddProps method to list properties to be included in or excluded from the TNEF encapsulation of a message or an attachment. Using successive calls, the provider or gateway can specify a list of properties to add and encode or to exclude from being encoded. Providers and gateways can also use AddProps to provide information on any special handling attachments should be given.

AddProps is only supported for TNEF objects opened with the TNEF_ENCODE flag for the OpenTnefStream or OpenTnefStreamEx function.

Note that no actual TNEF encoding happens for AddProps until the ITnef::Finish method is called. This functionality means that pointers passed into AddProps must remain valid until after the call to Finish is made. At that point, all objects and data passed in with AddProps calls can be released or freed.

See Also

ITnef::Finish, OpenTnefStream, OpenTnefStreamEx, PR_ATTACH_TRANSPORT_NAME


ITnef::EncodeRecips

The ITnef::EncodeRecips method encodes a view for a message's recipient table in the TNEF data stream for the message.

Quick Info

See ITnef : IUnknown.

HRESULT EncodeRecips(
  ULONG ulFlags,
  LPMAPITABLE lpRecipientTable
);

Parameters

ulFlags
Reserved; must be zero.
lpRecipientTable
[in] Pointer to the recipient table for which the view is encoded. The lpRecipientTable parameter can be NULL.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Transport providers, message store providers, and gateways call the ITnef::EncodeRecips method to perform TNEF encoding for a particular recipient table view. Such encoding is useful, for instance, if a provider or gateway requires a particular column set, sort order, or restriction for the recipient table.

A provider or gateway passes the table view to be encoded in lpRecipientTable. The TNEF implementation encodes the recipient table with the given view, using the given column set, sort order, restriction, and position. If a provider or gateway passes NULL in lpRecipientTable, TNEF gets the recipient table from the message being encoded, using the IMessage::GetRecipientTable method, and processes every row of the table into the TNEF stream using the table's current settings.

Calling EncodeRecips with NULL in lpRecipientTable thus encodes all message recipients and is equivalent to calling the ITnef::AddProps method with the TNEF_PROP_INCLUDE flag in its ulFlags parameter and the PR_MESSAGE_RECIPIENTS property in its lpPropList parameter.

Note that it is rarely necessary to call EncodeRecips unless there is some requirement for encoding a particular recipient table view. Foreign messaging systems almost always have facilities for handling recipient lists that are powerful enough to handle the common needs of encoding recipient lists and thus almost never require TNEF for this.

See Also

IMessage::GetRecipientTable, ITnef::AddProps, PR_MESSAGE_RECIPIENTS


ITnef::ExtractProps

The ITnef::ExtractProps method extracts the properties from a TNEF encapsulation.

Quick Info

See ITnef : IUnknown.

HRESULT ExtractProps(
  ULONG ulFlags,
  LPSPropTagArray lpPropList,
  LPSTnefProblemArray FAR * lpProblems
);

Parameters

ulFlags
[in] Bitmask of flags that controls how properties are decoded. The following flags can be set:
TNEF_PROP_EXCLUDE
Decodes all properties not specified in the lpPropList parameter.
TNEF_PROP_INCLUDE
Decodes all properties specified in lpPropList.
lpPropList
[in] Pointer to the list of properties to include in or exclude from the decoding operation.
lpProblems
[out] Pointer to a pointer to a returned STnefProblemArray structure. The STnefProblemArray structure indicates which properties were not encoded properly, if any. If NULL is passed in the lpProblems parameter, no property problem array is returned.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_CORRUPT_DATA
Data being decoded into a stream is corrupted.

Remarks

Transport providers, message store providers, and gateways call the ITnef::ExtractProps method to extract — that is, decode — properties from the encapsulation of a message or an attachment that was passed to the OpenTnefStream function. The calling provider or gateway can specify a list of properties to decode. Providers and gateways can also use ExtractProps to provide information on any special handling attachments should be given.

ExtractProps populates the original message passed into OpenTnefStream with the decoded properties. Subsequent ExtractProps calls go back to the message and extract the new list of properties.

Unlike the ITnef::AddProps method, which queues requested actions until the ITnef::Finish method is called, the ExtractProps method decodes the encapsulated properties immediately when it is called. For that reason, the target message for encapsulation decoding should be relatively empty. Existing properties in the target message are overwritten by encapsulated properties.

ExtractProps is only supported for objects opened with the TNEF_DECODE flag for the OpenTnefStream or OpenTnefStreamEx function.

The TNEF implementation reports TNEF stream encoding problems without halting the ExtractProps process. The STnefProblemArray structure returned in lpProblems indicates which TNEF attributes or MAPI properties, if any, could not be processed. The value returned in the scode member of the STnefProblemArray structure indicates the specific problem. The provider or gateway can work on the assumption that all properties or attributes for which ExtractProps does not return a problem report were processed successfully.

One exception is that if, during the decoding of a TNEF stream, a property in the MAPI encapsulation block cannot be processed and leaves the stream unreliable; then decoding of the encapsulation block is halted and a problem is reported. The problem array for this type of problem contains 0L for the ulPropTag member, attMAPIProps or attAttachment for the ulAttribute member, and MAPI_E_UNABLE_TO_COMPLETE for the scode member. Note that the decoding of the stream is not halted, just the decoding of the MAPI encapsulation block. The stream decoding continues with the next attribute block.

If a provider or gateway does not work with problem arrays, it can pass NULL in lpProblems; in this case, no problem array is returned.

The value returned in lpProblems is only valid if the call returns S_OK. When S_OK is returned, the provider or gateway should check the values returned in the STnefProblemArray structure. If an error occurs on the call, then the STnefProblemArray structure is not filled in and the calling provider or gateway should not use or free the structure. If no error occurs on the call, the calling provider or gateway must release the memory for the STnefProblemArray structure by calling the MAPIFreeBuffer function.

See Also

ITnef::AddProps, ITnef::Finish, ITnef::SetProps, MAPIFreeBuffer, OpenTnefStream, OpenTnefStreamEx, STnefProblemArray


ITnef::Finish

The ITnef::Finish method finishes processing for all TNEF operations that are queued and waiting.

Quick Info

See ITnef : IUnknown.

HRESULT Finish(
  ULONG ulFlags,
  WORD FAR * lpKey,
  LPSTnefProblemArray FAR * lpProblem
);

Parameters

ulFlags
Reserved; must be zero.
lpKey
[out] Pointer to the PR_ATTACH_NUM key property of an attachment. The TNEF encapsulation object uses this key to match an attachment to its attachment placement tag within a message. This key should be unique to each attachment.
lpProblem
[out] Pointer to a pointer to a returned STnefProblemArray structure. The STnefProblemArray structure indicates which properties were not encoded properly, if any. If NULL is passed in the lpProblem parameter, no property problem array is returned.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Transport providers, message store providers, and gateways call the ITnef::Finish method to perform the encoding of all properties for which encoding was requested in calls to the ITnef::AddProps and ITnef::SetProps methods. If the TNEF object was opened with the TNEF_ENCODE flag for the OpenTnefStream or OpenTnefStreamEx function, the Finish method encodes the requested properties into the encapsulation stream passed to that object. If the TNEF object was opened with the TNEF_DECODE flag, the Finish method decodes the properties from the TNEF stream and writes them back to the message they belong to.

After the Finish call, the pointer to the encapsulation stream points to the end of the TNEF data. If the provider or gateway needs to use the TNEF stream data after the Finish call, it must reset the stream pointer to the beginning of the TNEF stream data.

The TNEF implementation reports TNEF stream encoding problems without halting the Finish process. The STnefProblemArray structure returned in lpProblem indicates which TNEF attributes or MAPI properties, if any, could not be processed. The value returned in the scode member of the STnefProblemArray indicates the specific problem. The provider or gateway can work on the assumption that all properties or attributes for which Finish does not return a problem report were processed successfully.

If a provider or gateway does not work with problem arrays, it can pass NULL in lpProblem; in this case, no problem array is returned.

The value returned in lpProblem is only valid if the call returns S_OK. When S_OK is returned, the provider or gateway should check the values returned in the STnefProblemArray structure. If an error occurs on the call, then the STnefProblemArray structure is not filled in and the calling provider or gateway should not use or free the structure. If no error occurs on the call, the calling provider or gateway must release the memory for the STnefProblemArray by calling the MAPIFreeBuffer function.

See Also

ITnef::AddProps, MAPIFreeBuffer, OpenTnefStream, OpenTnefStreamEx, PR_ATTACH_NUM, STnefProblemArray


ITnef::FinishComponent

The ITnef::FinishComponent method processes individual components from a message one at a time into a TNEF stream.

Quick Info

See ITnef : IUnknown.

HRESULT FinishComponent(
  ULONG ulFlags,
  ULONG ulComponentID,
  LPSPropTagArray lpCustomPropList,
  LPSPropValue lpCustomProps,
  LPSPropTagArray lpPropList,
  LPSTnefProblemArray FAR * lppProblems
);

Parameters

ulFlags
[in] Bitmask of flags that controls which component will be finished. One or the other of the following flags must be set:
TNEF_COMPONENT_ATTACHMENT
Finish processing for an attachment object; the ulComponentID parameter contains the PR_ATTACH_NUM property of the attachment.
TNEF_COMPONENT_MESSAGE
Finish processing for a message object.
ulComponentID
[in] Zero to indicate processing for a message or the PR_ATTACH_NUM property of the attachment to be processed. If the TNEF_COMPONENT_MESSAGE flag is set in the ulFlags parameter, ulComponentID must be zero.
lpCustomPropList
[in] Pointer to an SPropTagArray structure that holds property tags identifying the properties passed in the lpCustomProps parameter. There must be a one-to-one correspondence between each property value in lpCustomProps and a property tag in the lpCustomPropList parameter.
lpCustomProps
[in] Pointer to an SPropValue structure containing property values for the properties to encode.
lpPropList
[in] Pointer to an SPropTagArray structure containing property tags for the properties to encode.
lppProblems
[out] Pointer to a pointer to a returned STnefProblemArray structure. The STnefProblemArray structure indicates which properties were not encoded properly, if any. If NULL is passed in the lppProblems parameter, no property problem array is returned.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Transport providers, message store providers, and gateways call the ITnef::FinishComponent method to perform TNEF processing for one component, either a message or an attachment, as indicated by the flag set in the ulFlags parameter.

For component processing to be enabled, the calling provider or gateway must have passed the TNEF_COMPONENT_ENCODING flag in ulFlags for the OpenTnefStream function or OpenTnefStreamEx function that opened the object to receive encoding.

Passing values in lpCustomPropList and lpCustomProps performs component encoding equivalent to that done by the ITnef::SetProps method. Passing a value in the lpPropList parameter performs component encoding equivalent to that done by the ITnef::AddProps method with the TNEF_PROP_INCLUDE flag set in ulFlags. Passing such values enables you to perform encodings with a single call rather than multiple calls.

The TNEF implementation reports TNEF stream encoding problems without halting the FinishComponent process. The STnefProblemArray structure returned in lppProblems indicates which TNEF attributes or MAPI properties, if any, could not be processed. The value returned in the scode member of the STnefProblemArray structure indicates the specific problem. The provider or gateway can work on the assumption that all properties or attributes for which FinishComponent does not return a problem report were processed successfully.

If a provider or gateway does not work with problem arrays, it can pass NULL in lppProblems; in this case, no problem array is returned.

The value returned in lppProblems is only valid if the call returns S_OK. When S_OK is returned, the provider or gateway should check the values returned in the STnefProblemArray structure. If an error occurs on the call, then the STnefProblemArray structure is not filled in and the calling provider or gateway should not use or free the structure. If no error occurs on the call, the calling provider or gateway must release the memory for the STnefProblemArray by calling the MAPIFreeBuffer function.

See Also

ITnef::AddProps, ITnef::SetProps, MAPIFreeBuffer, OpenTnefStream, OpenTnefStreamEx, SPropTagArray, STnefProblemArray


ITnef::OpenTaggedBody

The ITnef::OpenTaggedBody method opens a stream interface on the text of an encapsulated message.

Quick Info

See ITnef : IUnknown.

HRESULT OpenTaggedBody(
  LPMESSAGE lpMessage,
  ULONG ulFlags,
  LPSTREAM FAR * lppStream
);

Parameters

lpMessage
[in] Pointer to the message the stream is associated with. This message is not required to be the same message passed in the call to the OpenTnefStream or OpenTnefStreamEx function.
ulFlags
[in] Bitmask of flags that controls how the stream interface is opened. The following flags can be set:
MAPI_CREATE
If a property does not exist in the current message, it should be created. If the property does exist, the current data in the property should be replaced with the data from the TNEF stream. When an implementation sets the MAPI_CREATE flag, it should also set the MAPI_MODIFY flag.
MAPI_MODIFY
Requests read/write access. The default interface is read-only. MAPI_MODIFY must be set whenever MAPI_CREATE is set.
lppStream
[out] Pointer to the pointer to a stream object that contains the text from the PR_BODY property of the passed-in encapsulated message and that supports the IStream interface.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Transport providers, message store providers, and gateways call the ITnef::OpenTaggedBody method to open a stream interface on the text of an encapsulated message — that is, on a TNEF object.

As part of its processing, OpenTaggedBody either inserts or parses attachment tags that indicate the position of any attachments or OLE objects within the message text. The attachment tags are in the following format:

[[ attachment name : n in attachment container name ]]

where attachment name describes the attachment object; n is a number identifying the attachment that is part of a sequence, incrementing from the value passed in the lpKey parameter of the OpenTnefStream or OpenTnefStreamEx function; and attachment container name describes the physical component where the attachment object resides.

OpenTaggedBody reads out message text and inserts an attachment tag wherever an attachment object originally appeared in the text. The original message text is not changed.

When a message that has tags is passed to a stream, the tags are stripped out and the attachment objects are relocated in the position of the tags in the stream.

See Also

OpenTnefStream, OpenTnefStreamEx, PR_BODY


ITnef::SetProps

The ITnef::SetProps method sets the value of one or more properties for an encapsulated message or attachment without modifying the original message or attachment.

Quick Info

See ITnef : IUnknown.

HRESULT SetProps(
  ULONG ulFlags,
  ULONG ulElemID,
  ULONG cValues,
  LPSPropValue lpProps
);

Parameters

ulFlags
[in] Bitmask of flags that controls how properties' values are set. The following flag can be set:
TNEF_PROP_CONTAINED
Encodes only properties from the message or attachment specified by the ulElemID parameter.
ulElemID
[in] An attachment's PR_ATTACH_NUM property, which holds a number that uniquely identifies the attachment within its parent message.
cValues
[in] Number of property values in the SPropValue structure pointed to by the lpProps parameter.
lpProps
[in] Pointer to an SPropValue structure containing the property values of the properties to set.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Transport providers, message store providers, and gateways call the ITnef::SetProps method to set properties to include in the encapsulation of a message or an attachment without modifying the original message or attachment. Any properties set with this call override existing properties in the encapsulated message.

SetProps is only supported for TNEF objects opened with the TNEF_ENCODE flag for the OpenTnefStream or OpenTnefStreamEx function. Any number of properties can be set with this call.

Note that no actual TNEF encoding for SetProps happens until after the ITnef::Finish method is called. This functionality means that pointers passed into SetProps must remain valid until after the call to Finish is made. At that point, all objects and data passed into SetProps calls can be released or freed.

See Also

ITnef::Finish, OpenTnefStream, OpenTnefStreamEx, PR_ATTACH_NUM, SPropValue


IXPLogon : IUnknown

The IXPLogon interface is used to give the MAPI spooler access to a transport provider.

Quick Info

Header file: | MAPISPI.H
Exposed by: | Transport logon objects
Implemented by: | Transport providers
Called by: | The MAPI spooler
Interface identifier: | IID_IXPLogon
Pointer type: | LXPLOGON

Vtable Order

AddressTypes | Returns the types of recipients that the transport provider handles.
RegisterOptions | Returns the options that are supported by the transport provider for an address type to the MAPI spooler.
TransportNotify | Signals the occurrence of an event about which the transport provider has requested notification.
Idle | Indicates that the system is idle, allowing the transport provider to perform low-priority operations.
TransportLogoff | Initiates the logoff process.
SubmitMessage | Indicates that the MAPI spooler has a message for the transport provider to deliver.
EndMessage | Informs the transport provider that the MAPI spooler has completed its processing on an outbound message.
Poll | Indicates whether or not the transport provider has received one or more inbound messages.
StartMessage | Initiates the transfer of an inbound message from the transport provider to the MAPI spooler.
OpenStatusEntry | Opens the transport provider's status object.
ValidateState | Checks the transport provider's external status.
FlushQueues | Requests that the transport provider immediately deliver all pending inbound or outbound messages.


IXPLogon::AddressTypes

The IXPLogon::AddressTypes method returns the types of recipients that the transport provider handles.

Quick Info

See IXPLogon : IUnknown.

HRESULT AddressTypes(
  ULONG FAR * lpulFlags,
  ULONG FAR * lpcAdrType,
  LPTSTR FAR * FAR * lpppszAdrTypeArray,
  ULONG FAR * lpcMAPIUID,
  LPUID FAR * FAR * lpppUIDArray
);

Parameters

lpulFlags
[out] Bitmask of flags that controls the type of the returned strings. The following flag can be set:
MAPI_UNICODE
The returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lpcAdrType
[out] Pointer to the count of entries in the array pointed to by the lpppszAdrTypeArray parameter.
lpppszAdrTypeArray
[out] Pointer to a pointer to an array of strings that identify recipient types.
lpcMAPIUID
[out] Pointer to a count of entries in the array pointed to by the lpppUIDArray parameter.
lpppUIDArray
[out] Pointer to a pointer to an array of pointers to MAPIUID structures that identify recipient types.

Return Values

S_OK
The transport provider has successfully indicated the types of recipient that it can handle.

Notes to Implementers

The MAPI spooler calls the IXPLogon::AddressTypes method immediately after a transport provider returns from a call to the IXPProvider::TransportLogon method so the transport provider can indicate what types of recipients it handles. To indicate this, the transport provider should pass back in the lpppszAdrTypeArray parameter a pointer to an array of pointers to strings, or pass back in the lpppUIDArray parameter a pointer to an array of pointers to MAPIUID structures, or pass values in both parameters.

These two arrays are used for different identification processes. MAPI and the MAPI spooler use the MAPIUID structures in the lpppUIDArray array to identify those recipient entry identifiers that are directly handled by the transport provider or by the messaging system to which the transport provider connects. Neither MAPI nor the MAPI spooler performs expansion of addresses with entry identifiers contained in any of these MAPIUID structures; these structures are only used for recipient type identification.

The MAPI spooler uses each of the strings in the lpppszAdrTypeArray parameter for a comparison test when deciding which transport provider should handle which recipients for an outbound message. If a message recipient's PR_ADDRTYPE property exactly matches a string identifying one of the messaging address types supplied by the transport provider, the provider can deliver the message to that recipient.

In the event multiple transport providers can handle the same type of recipient, MAPI selects a transport provider based on the transport priority order indicated in the client application's profile. To determine which transport provider to use, the MAPI spooler scans all provider-specified MAPIUID structures in priority order, then all provider-specified address type values in priority order. The first transport provider to match a particular recipient in this scan gets the first opportunity to handle this recipient. If that provider does not handle the recipient, the MAPI spooler continues the scan so as to find a transport provider for any recipient not yet handled. The scan continues until no further matches are found, at which point a nondelivery report is generated for any recipient that was not handled.

If the provider always supports a particular set of recipient types, the address type and MAPIUID arrays passed by the transport provider can be static. If the transport provider dynamically constructs these arrays, it can use the support object that was passed in the call to TransportLogon directly previous to allocate memory, although this is not strictly necessary.

The memory used for the address type and MAPIUID arrays should remain allocated until the final call to the IXPLogon::TransportLogoff method is performed, at which time the transport provider can free the memory if necessary. The contents of these arrays should not be altered by the transport provider after returning from the TransportLogoff call.

A transport provider that can handle any type of recipient can return NULL in lpppszAdrTypeArray. Transport providers for LAN-based messaging systems that use a central server to deliver outgoing messages to various foreign message systems commonly do this. Such a transport provider should be installed last in the MAPI and MAPI spooler priority order of transport providers within the profile.

A transport provider that does not support outbound messages dispatched to it based on address type should return a single zero-length string in lpppszAdrTypeArray. If a transport provider supports no recipient types, it should pass NULL for the MAPIUID structure and an empty string for the address type. Transport providers of this type are most commonly used as a vehicle for installing a message preprocessor. See Developing a Hook Provider or Preprocessor.

For more information on working with address types, see Displaying and Editing Addresses with Simple MAPI .

See Also

IXPLogon::TransportLogoff, IXPProvider::TransportLogon, MAPIUID


IXPLogon::EndMessage

The IXPLogon::EndMessage method informs the transport provider that the MAPI spooler has completed its processing on an outbound message.

Quick Info

See IXPLogon : IUnknown.

HRESULT EndMessage(
  ULONG ulMsgRef,
  ULONG FAR * lpulFlags
);

Parameters

ulMsgRef
[in] A 32-bit reference value, specific to a message, obtained in an earlier call to the IXPLogon::SubmitMessage method.
lpulFlags
[out] Bitmask of flags that indicates to the MAPI spooler what it should do with the message. If no flags are set, the message has been sent. The following flags can be set:
END_DONT_RESEND
The transport provider has all the information it needs about this message for now. When the transport provider requires more information or when it has completed sending the message, it notifies the MAPI spooler by calling the IMAPISupport::SpoolerNotify method with the NOTIFY_SENTDEFERRED flag and by passing the message's entry identifier.
END_RESEND_LATER
The transport provider isn't sending the message now for reasons that are not error conditions and should be called again later to send the message.
END_RESEND_NOW
The transport provider needs to restart the message passed to it in an IMessage::SubmitMessage method call.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

The MAPI spooler calls the IXPLogon::EndMessage method after completing the processing involved in providing extended delivery or nondelivery information.

Once this call returns, the value in the ulMsgRef parameter is no longer valid for this message. The transport provider can reuse the same value on a future message.

All objects opened by the transport provider during the transfer of a message should be released before returning from the EndMessage call, with the exception of the message object the MAPI spooler passes to the transport provider. The message object passed by the MAPI spooler is invalid after the EndMessage call.

See Also

IMAPISupport::SpoolerNotify, IMessage::SubmitMessage, IXPLogon::SubmitMessage


IXPLogon::FlushQueues

The IXPLogon::FlushQueues method requests that the transport provider immediately deliver all pending inbound or outbound messages.

Quick Info

See IXPLogon : IUnknown.

HRESULT FlushQueues(
  ULONG ulUIParam,
  ULONG cbTargetTransport,
  LPENTRYID lpTargetTransport,
  ULONG ulFlags
);

Parameters

ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays.
cbTargetTransport
Reserved; must be zero.
lpTargetTransport
Reserved; must be NULL.
ulFlags
[in] Bitmask of flags that controls how message queue flushing is done. The following flags can be set:
FLUSH_DOWNLOAD
The inbound message queue or queues should be flushed.
FLUSH_FORCE
The transport provider should process this request if possible, even if doing so is time-consuming.
FLUSH_NO_UI
The transport provider should not display a user interface.
FLUSH_UPLOAD
The outbound message queue or queues should be flushed.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

The MAPI spooler calls the IXPLogon::FlushQueues method to advise the transport provider that the MAPI spooler is about to begin processing messages. The transport provider should call the IMAPISupport::ModifyStatusRow method to set an appropriate bit for its state in the PR_STATUS_CODE property of its status row. After updating its status row, the transport provider should return S_OK for the FlushQueues call. The MAPI spooler then starts sending messages, with the operation being synchronous to the MAPI spooler.

To support its implementation of the IMAPIStatus::FlushQueues method, the MAPI spooler calls IXPLogon::FlushQueues for all logon objects for active transport providers running in a profile session. When a transport provider's FlushQueues method is called as a result of a client application calling IMAPIStatus::FlushQueues, the message processing occurs asynchronously to the client.

See Also

IMAPIStatus::FlushQueues


IXPLogon::Idle

The IXPLogon::Idle method indicates that the system is idle, allowing the transport provider to perform low-priority operations.

Quick Info

See IXPLogon : IUnknown.

HRESULT Idle(
  ULONG ulFlags
);

Parameters

ulFlags
Reserved; must be zero.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

The MAPI spooler periodically calls the IXPLogon::Idle method during times when the system is idle if requested by passing the XP_LOGON_SP flag in the call to the IXPProvider::TransportLogon method that opened the current session. At times when the system is idle, the transport provider can perform background operations that are not appropriate during other calls, or that need to occur on a regular basis.

See Also

IXPProvider::TransportLogon


IXPLogon::OpenStatusEntry

The IXPLogon::OpenStatusEntry method opens the transport provider's status object.

Quick Info

See IXPLogon : IUnknown.

HRESULT OpenStatusEntry(
  LPCIID lpInterface,
  ULONG ulFlags,
  ULONG FAR * lpulObjType,
  LPMAPISTATUS FAR * lppEntry
);

Parameters

lpInterface
[in] Pointer to an interface identifier (IID) for the transport logon object. Passing NULL indicates the IMAPIStatus interface is returned. The lpInterface parameter can also be set to an identifier for an interface for the object.
ulFlags
[in] Bitmask of flags that controls how the status object is opened. The following flag can be set:
MAPI_MODIFY
Requests read/write access. The default interface is read-only.
lpulObjType
[out] Pointer to the type of the opened object.
lppEntry
[out] Pointer to the pointer to the opened status object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

The MAPI spooler calls the IXPLogon::OpenStatusEntry method when a client application calls an OpenEntry method for the entry identifier in the transport provider's status table row. OpenStatusEntry opens an object with the IMAPIStatus interface associated with this particular transport provider logon. This object is then used to enable client applications to call IMAPIStatus methods, for example to reconfigure the logon session using the IMAPIStatus::SettingsDialog method, or to validate the state of the logon session using the IMAPIStatus::ValidateState method.

See Also

IMAPIStatus : IMAPIProp


IXPLogon::Poll

The IXPLogon::Poll method indicates whether or not the transport provider has received one or more inbound messages.

Quick Info

See IXPLogon : IUnknown.

HRESULT Poll(
  ULONG FAR * lpulIncoming
);

Parameters

lpulIncoming
[out] Value indicating the existence of inbound messages. A nonzero value indicates that there are inbound messages.

Returned Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

The MAPI spooler periodically calls the IXPLogon::Poll method if the transport provider indicates it must be polled for new messages; it does so by passing the LOGON_SP_POLL flag to the call to the IXPProvider::TransportLogon method at the beginning of a session. If the transport provider indicates in response to the Poll call that there are one or more inbound messages available for it to process, the MAPI spooler calls the IXPLogon::StartMessage method to allow the provider to process the first inbound message. The transport provider indicates inbound messages by setting the value in the Poll lpulIncoming parameter to nonzero.

See Also

IXPLogon::StartMessage, IXPProvider::TransportLogon


IXPLogon::RegisterOptions

The IXPLogon::RegisterOptions method returns the options that are supported by the transport provider for an address type to the MAPI spooler.

Quick Info

See IXPLogon : IUnknown.

HRESULT RegisterOptions(
  ULONG FAR * lpulFlags,
  ULONG FAR * lpcOptions,
  LPOPTIONDATA FAR * lppOptions
);

Parameters

lpulFlags
[out] Bitmask of flags that controls the type of the returned strings. The following flag can be set:
MAPI_UNICODE
The returned strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lpcOptions
[out] Pointer to the number of options contained in the structure returned in the lppOptions parameter.
lppOptions
[out] Pointer to a pointer to the returned OPTIONDATA structure. The OPTIONDATA structure contains information for a particular messaging address type.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

If anything other than S_OK is returned, the provider is logged off.

Remarks

The MAPI spooler calls the IXPLogon::RegisterOptions method to get the options for messages and recipients supported by a transport provider for a particular messaging address type. These options are then registered with MAPI so they can be displayed in options dialog boxes.

RegisterOptions returns in the lppOptions parameter pointers to one or two OPTIONDATA structures for each supported messaging address type, depending on whether the provider is registered for both recipient and message options, recipient options only, or message options only. If a provider is registered for both option types, RegisterOptions writes one structure containing option information for recipients and one containing option information for messages. For each structure, the ulFlags member indicates whether the options apply to a recipient or a message.

For an example of the use of OPTIONDATA, consider a transport provider that handles recipients for both Microsoft® Mail Server and Microsoft® Mail Server for the Macintosh. If the provider is registered for both recipient and message options, it provides two pairs of OPTIONDATA structures, one pair for each platform. The MAPI spooler can use these structures to determine what options are valid for each platform and to allow users to change settings for those options.

MAPI also uses the options registered on the RegisterOptions call to resolve message and recipient options. MAPI does so by using a callback function that the transport provider supplies; this callback function, declared with the OPTIONCALLBACK function prototype defined in MAPIDEFS.H, receives a wrapped IMAPIProp interface that manages the provider's message and recipient properties.

The transport provider is responsible for memory allocated for any OPTIONDATA structures during this call. The provider should free the memory upon logoff.

See Also

IXPLogon::RegisterOptions, OPTIONCALLBACK, OPTIONDATA


IXPLogon::StartMessage

The IXPLogon::StartMessage method initiates the transfer of an inbound message from the transport provider to the MAPI spooler.

Quick Info

See IXPLogon : IUnknown.

HRESULT StartMessage(
  ULONG ulFlags,
  LPMESSAGE lpMessage,
  ULONG FAR * lpulMsgRef
);

Parameters

ulFlags
Reserved; must be zero.
lpMessage
[in] Pointer to a message object with read/write access, representing the inbound message, which is used by the transport provider to access and manipulate that message. This object remains valid until after the transport provider returns from the call to IXPLogon::StartMessage.
lpulMsgRef
[out] Pointer to a 32-bit reference value assigned to the message. This value is initialized to 1 by the MAPI spooler before returning it to the transport provider.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

The MAPI spooler calls the IXPLogon::StartMessage method to initiate the transfer of an inbound message from the transport provider to the MAPI spooler. Before the transport provider starts to use the message pointed to by lpMessage, it should store a message reference in the lpulMsgRef parameter for potential use by a call to the IXPLogon::TransportNotify method.

During a StartMessage call, the MAPI spooler processes methods for objects opened during the transfer of the message and also processes any attachments. This processing can take a long time. Transport providers on 16-bit Windows platforms should call the IMAPISupport::SpoolerYield callback function for the MAPI spooler frequently during this processing to release CPU time for other system tasks.

All recipients in the recipient table created by the transport provider for the message must contain all required addressing properties. If necessary, the provider can construct a custom recipient to represent a particular recipient. However, if the provider can produce a recipient entry that includes more information, it should do so. For example, in the case where a transport provider has enough information about an address book provider's recipient format that it can build a valid entry identifier for a recipient for that format, it should build the entry identifier.

If any nontransmittable properties are received, the transport provider should not store them in the new message. However, the transport provider should store all transmittable properties it receives in the new message.

If the incoming message is a delivery report or a nondelivery report and the transport provider is unable to use the IMAPISupport::StatusRecips method to generate the report from the original message, the provider should itself populate the message with the appropriate properties. However, the transport provider cannot set the message's PR_ENTRYID property.

To save the incoming message in the appropriate MAPI message store after processing, the transport provider calls the IMAPIProp::SaveChanges method. If the transport provider doesn't have any messages to pass to the MAPI spooler, it can stop the incoming message by returning from the StartMessage call without calling SaveChanges.

All objects opened by the transport provider during a StartMessage call should be released before returning. However, the provider should not release the message object originally passed by the MAPI spooler in the lpMessage parameter.

If an error is returned from StartMessage, the message in process is released without having changes saved and is lost. The transport provider in such a case should pass the NOTIFY_CRITICAL_ERROR flag with a call to the IMAPISupport::SpoolerNotify method and call the IXPLogon::Poll method to notify the MAPI spooler that it is in a severe error condition.

For more information, see Interacting with the MAPI Spooler.

See Also

IMAPIProp::SaveChanges, IMAPISupport::SpoolerNotify, IMAPISupport::SpoolerYield, IMAPISupport::StatusRecips, IMessage::GetRecipientTable, IXPLogon::Poll, IXPLogon::TransportNotify


IXPLogon::SubmitMessage

The IXPLogon::SubmitMessage method indicates that the MAPI spooler has a message for the transport provider to deliver.

Quick Info

See IXPLogon : IUnknown.

HRESULT SubmitMessage(
  ULONG ulFlags,
  LPMESSAGE lpMessage,
  ULONG FAR * lpulMsgRef,
  ULONG FAR * lpulReturnParm
);

Parameters

ulFlags
[in] Bitmask of flags that controls how the message is submitted. The following flag can be set:
BEGIN_DEFERRED
The MAPI spooler is calling a transport provider with a message that was previously deferred. The entry identifier of the message is the same as when it was deferred. The message was deferred by passing its entry identifier back to the MAPI spooler using the IMAPISupport::SpoolerNotify method with the NOTIFY_SENTDEFERRED flag.
lpMessage
[in] Pointer to a message object with read/write access, representing the message to deliver, which is used by the transport provider to access and manipulate that message. This object remains valid until after the transport provider returns from a subsequent call to the IXPLogon::EndMessage method.
lpulMsgRef
[out] Pointer to a variable in which the transport provider returns the 32-bit reference value it assigned to this message. The MAPI spooler passes this reference value in subsequent calls for this message. The value is initialized to zero by the MAPI spooler before returning it to the transport provider.
lpulReturnParm
[out] Pointer to a variable that corresponds to the MAPI_E_WAIT or MAPI_E_NETWORK_ERROR error value returned by IXPLogon::SubmitMessage.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_BUSY
The transport provider can't handle the message because it is performing another operation. A provider should use this return value to indicate that no processing occurred and that the MAPI spooler should not call EndMessage. The MAPI spooler tries the SubmitMessage call again later.
MAPI_E_CANCEL
Although on a previous SpoolerNotify call the transport provider requested the MAPI spooler resubmit the message, conditions have since changed and the message should not be resent. The MAPI spooler goes on to handle something else.
MAPI_E_NETWORK_ERROR
A network error prevented successful completion of the operation. The lpulReturnParm parameter should be set to the number of seconds before the MAPI spooler resubmits the message.
MAPI_E_NOT_ME
The transport provider cannot handle this message. The MAPI spooler should try to find another transport provider for it. A provider should use this return value to indicate that no processing occurred and that the MAPI spooler should not call EndMessage.
MAPI_E_WAIT
A temporary problem prevents the transport provider from handling the message. The lpulReturnParm parameter should be set to the number of seconds before the MAPI spooler resubmits the message.

Remarks

The MAPI spooler calls the IXPLogon::SubmitMessage method when it has a message for the transport provider to deliver. The message is passed to the transport provider using the lpMessage parameter.

If the provider is ready to accept the message, it should return a reference value by using the lpulMsgRef parameter, process the passed object, and return the appropriate value, usually s_ok. If the provider is not prepared to handle the transfer, it should return an error value and, optionally, another MAPI return value in lpulReturnParm to indicate how long the MAPI spooler should wait before resubmitting the message.

A transport provider's implementation of this method can:

  • Put the message into an internal queue to wait for transmission, possibly copying it to local storage, and return.
  • Attempt to perform the actual transmission and return when the transmission has completed, either successfully or unsuccessfully.
  • Determine whether or not to send the message after checking the resource involved. In this case, if the resource is free, the provider can lock the resource, prepare the message, and submit it. If the resource is busy, the provider can prepare the message and defer sending to a later time.

The preferred technique depends on the transport provider and the expected number of processes competing for system resources.

During a SubmitMessage call, the transport provider controls the transfer of message data from the message object. However, the transport provider should assign a 32-bit reference value to the message, to which it returns a pointer in lpulMsgRef, before transferring data. It does so because at any point during the process the MAPI spooler can call the IXPLogon::TransportNotify method with the NOTIFY_CANCEL_MESSAGE flag set to signal the provider it should release any open objects and stop message transfer.

The transport provider should not send any nontransmittable properties of the message. When it finds such a property, it should go on to process the next one. The provider should make every effort not to display MAPI_P1 recipient information as part of the transmitted message content, using such recipient information only for addressing purposes. MAPI_P1 recipients are internally-generated recipients for use in resends, they should not be transmitted. Instead, use the other recipients for transmitting recipient information. The purpose of this arrangement is to permit resend recipients to see the exact same recipient table as the original recipients.

During a SubmitMessage call, the MAPI spooler processes methods for objects opened during the transfer of the message and also processes any attachments. This processing can take a long time. Transport providers running on 16-bit Windows platforms should call the IMAPISupport::SpoolerYield method for the MAPI spooler frequently during this processing to release CPU time for other system tasks.

All message recipients are visible in the recipient table of the message originally passed by the MAPI spooler. The transport provider should process only those recipients that it can handle based on entry identifier, address type, or both, and that do not already have their PR_RESPONSIBILITY property set to TRUE. If PR_RESPONSIBILITY is already set to TRUE, another transport provider has handled that recipient. When the provider has completed sufficient processing of a recipient to determine whether it can handle messages for that recipient, it should set that recipient's PR_RESPONSIBILITY property to TRUE in the passed message. Usually, the provider makes this determination after message delivery is complete.

Typically, the transport provider does not return from a SubmitMessage call until it has completed the transfer of message data. If no error is returned, the next call from the MAPI spooler to the provider is a call to the IXPLogon::EndMessage method.

If an error is returned from SubmitMessage, the MAPI spooler releases the message in process without saving changes. If the transport provider requires message changes be saved, it must call the IMAPIProp::SaveChanges method on the message before returning.

In case of errors occurring because of transport problems, the MAPI spooler retains the message but delays resubmitting it to the transport provider based on the value returned in lpulReturnParm. The transport provider must fill in that value if its return from SubmitMessage is MAPI_E_WAIT or MAPI_E_NETWORK_ERROR. If a severe error condition is occurring, the transport provider must call the IMAPISupport::SpoolerNotify method with the NOTIFY_CRITICAL_ERROR flag.

See Also

IMAPIProp::SaveChanges, IMAPISupport::SpoolerNotify, IMAPISupport::SpoolerYield, IXPLogon::EndMessage, IXPLogon::TransportNotify


IXPLogon::TransportLogoff

The IXPLogon::TransportLogoff method initiates the logoff process.

Quick Info

See IXPLogon : IUnknown.

HRESULT TransportLogoff(
  ULONG ulFlags
);

Parameters

ulFlags
Reserved; must be zero.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

If anything other than S_OK is returned, the provider is logged off.

Remarks

The MAPI spooler calls the IXPLogon::TransportLogoff method to terminate a transport provider session for a particular user. Before calling TransportLogoff, the MAPI spooler discards any data about supported messaging address types for this session passed in the IXPLogon::AddressTypes method.

Notes to Implementers

The transport provider should be prepared to accept a call to TransportLogoff at any time. If a message is in process, the provider should stop the sending process.

The transport provider should release all resources allocated for its current session. If it has allocated any memory for this session with the MAPIAllocateBuffer function, it should free the memory by using the MAPIFreeBuffer function. Any memory allocated by the transport provider to satisfy calls to the IXPLogon::AddressTypes, IXPLogon::RegisterOptions, and IMAPISession::MessageOptions methods can be safely released at this time.

Usually, a provider should, on completing a TransportLogoff call, first invalidate its logon object by calling the IMAPISupport::MakeInvalid method and then release its support object. The provider's implementation of TransportLogoff should release the support object last because when the support object is released, the MAPI spooler can also release the provider object itself.

See Also

IMAPISession::MessageOptions, IMAPISupport::MakeInvalid, IMAPISupport::SpoolerYield, IXPLogon::AddressTypes, IXPLogon::RegisterOptions, MAPIAllocateBuffer, MAPIFreeBuffer


IXPLogon::TransportNotify

The IXPLogon::TransportNotify method signals the occurrence of an event about which the transport provider has requested notification.

Quick Info

See IXPLogon : IUnknown.

HRESULT TransportNotify(
  ULONG FAR * lpulFlags,
  LPVOID FAR * lppvData
);

Parameters

lpulFlags
[in, out] Bitmask of flags that signals notification events. The following flags can be set by the MAPI spooler on input and must be returned unchanged on output:
NOTIFY_ABORT_DEFERRED
Notifies the transport provider that a message for which it accepted responsibility is being deferred. Only transport providers that support deferral must support this flag. The lppvData parameter points to the entry identifier of the canceled message. Messages that have not been processed by the MAPI spooler can still be deferred by calling the IMsgStore::AbortSubmit method.
NOTIFY_BEGIN_INBOUND
The MAPI spooler can now accept inbound messages for this transport provider session. The MAPI spooler regularly calls the IXPLogon::Poll method if the transport provider set the flag LOGON_SP_POLL with the IXPProvider::TransportLogon call at logon. Once the NOTIFY_BEGIN_INBOUND flag is set, the MAPI spooler honors the NOTIFY_NEWMAIL flag passed in the call to the IMAPISupport::SpoolerNotify method. The status table row for the transport provider session should be updated before returning by calling the IMAPISupport::ModifyStatusRow method. NOTIFY_BEGIN_INBOUND is mutually exclusive with the NOTIFY_END_INBOUND flag.
NOTIFY_BEGIN_INBOUND_FLUSH
Signals the transport provider to cycle through inbound messages as quickly as possible. To comply with this notification, the transport provider should set the flag STATUS_INBOUND_FLUSH in the PR_STATUS_CODE property of its status table row as soon as it can, using ModifyStatusRow. Until the end of this inbound messaging cycle, which is when the provider determines it has downloaded all it can or when it has received an IXPLogon::TransportNotify method call with the flag NOTIFY_END_INBOUND_FLUSH set, the provider should not call the IMAPISupport::SpoolerYield method or otherwise give up cycles to the operating system in order to speed delivery of incoming messages. This is acceptable because the MAPI spooler typically only uses this notification in response to a user's request, via a client application, to deliver all messages now. At the end of the inbound flush operation, the provider should use SpoolerNotify to clear the STATUS_INBOUND_FLUSH flag in the PR_STATUS_CODE property of its status row.
NOTIFY_BEGIN_OUTBOUND
Outbound operations can now occur for this transport provider session. If there are any messages to be sent for this provider, a call to the IXPLogon::SubmitMessage method follows. The status table row for this session should be updated before returning. The NOTIFY_BEGIN_OUTBOUND flag is mutually exclusive with the NOTIFY_END_OUTBOUND flag.
NOTIFY_BEGIN_OUTBOUND_FLUSH
Works similarly to the NOTIFY_BEGIN_INBOUND_FLUSH flag but refers to outbound messages, and the appropriate status flag is STATUS_OUTBOUND_FLUSH.
NOTIFY_CANCEL_MESSAGE
The MAPI spooler must cancel transfer of the message for which the lppvData parameter points to the 32-bit value obtained with the IXPLogon::SubmitMessage method call. The NOTIFY_CANCEL_MESSAGE flag can be set without the transport provider having returned from the SubmitMessage, IXPLogon::StartMessage, or IXPLogon::EndMessage method call associated with the message. The transport provider must return from the entry point that is handling the canceled message as soon as possible.

For an inbound message that is currently being processed, the transport provider should save the incoming message wherever it is presently stored and deliver it again at the next convenient time. The message object data already stored for the incoming message is discarded.

If the transport provider did not update this 32-bit value at StartMessage or SubmitMessage time, it is 0 for outbound messages and 1 for inbound messages.

NOTIFY_END_INBOUND
Inbound operations must cease for this transport provider session. The MAPI spooler ceases to use Poll and ignores NOTIFY_NEWMAIL for this session. In-process messages should be completed. The status table row for the transport session should be updated by calling ModifyStatusRow before returning. NOTIFY_END_INBOUND is mutually exclusive with NOTIFY_BEGIN_INBOUND.
NOTIFY_END_INBOUND_FLUSH
Notifies the transport provider to come out of inbound flush mode. The transport provider should not stop downloading, but downloading should be done in the background. The status table row for the transport session should be updated by calling ModifyStatusRow when the transport provider can comply with this notification.
NOTIFY_END_OUTBOUND
Outbound operations must cease for this transport provider session. The MAPI spooler ceases to call SubmitMessage and ignores the SpoolerNotify flag NOTIFY_READYTOSEND. If there is an outbound message currently being sent, it should not be stopped; to stop delivery of a message, use the NOTIFY_CANCEL_MESSAGE flag. The status table row for this session should be updated by calling ModifyStatusRow before returning. NOTIFY_END_INBOUND is mutually exclusive with NOTIFY_BEGIN_OUTBOUND.
NOTIFY_END_OUTBOUND_FLUSH
Works similarly to NOTIFY_END_INBOUND_FLUSH but refers to outbound messages, and the appropriate status flag is STATUS_OUTBOUND_FLUSH.
lppvData
[out] Pointer to a pointer to event-specific data. For more information on what lppvData holds, see the description for the lpulFlags parameter.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

The MAPI spooler calls the IXPLogon::TransportNotify method to signal to the transport provider the occurrence of events about which notification has been requested. These events include the MAPI spooler's requiring the cancellation of transfer for a message, the beginning or ending of inbound or outbound transport operations, and the beginning or ending of an operation to clear an inbound or outbound message queue.

When the user tries to cancel a message that the transport provider has previously deferred, the MAPI spooler calls TransportNotify passing in both the NOTIFY_ABORT_DEFERRED and NOTIFY_CANCEL_MESSAGE flags in ulFlags. If the MAPI spooler is logging off and still has messages in the queue, it passes only NOTIFY_ABORT_DEFERRED in ulFlags when it calls TransportNotify.

Notes to Implementers

The provider must synchronize access to its data on this call because the MAPI spooler can invoke this method from another thread of execution or from a procedure for a different window. This is most likely when the MAPI spooler signals the cancellation of a message that the transport provider has started sending.

See Also

IMAPISupport::SpoolerNotify, IMAPISupport::SpoolerYield, IMsgStore::AbortSubmit, IXPLogon::EndMessage, IXPLogon::Poll, IXPLogon::StartMessage, IXPLogon::SubmitMessage, IXPLogon::TransportNotify, IXPProvider::TransportLogon


IXPLogon::ValidateState

The IXPLogon::ValidateState method checks the transport provider's external status.

Quick Info

See IXPLogon : IUnknown.

HRESULT ValidateState(
  ULONG ulUIParam,
  ULONG ulFlags
);

Parameters

ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays.
ulFlags
[in] Bitmask of flags that controls how the status check is done and its results. The following flags can be set:
ABORT_XP_HEADER_OPERATION
The user canceled the operation, typically by clicking the Cancel button in a dialog box. The transport provider has the option to continue working on the operation, or it can abort the operation and return MAPI_E_USER_CANCELED.
CONFIG_CHANGED
Validates the state of currently loaded transport providers by causing the MAPI spooler to call their IXPLogon::AddressTypes and IMAPISession::MessageOptions methods. This flag also provides the MAPI spooler an opportunity to correct critical transport-provider failures without forcing client applications to log off and then log on again.
FORCE_XP_CONNECT
The user selected a connect operation. When this flag is used with the REFRESH_XP_HEADER_CACHE or PROCESS_XP_HEADER_CACHE flag, the connect action occurs without caching.
FORCE_XP_DISCONNECT
The user selected a disconnect operation. When this flag is used with REFRESH_XP_HEADER_CACHE or PROCESS_XP_HEADER_CACHE, the disconnect action occurs without caching.
PROCESS_XP_HEADER_CACHE
Entries in the header cache table should be processed, all messages marked with the MSGSTATUS_REMOTE_DOWNLOAD flag should be downloaded, and all messages marked with the MSGSTATUS_REMOTE_DELETE flag should be deleted. Messages that have both MSGSTATUS_REMOTE_DOWNLOAD and MSGSTATUS_REMOTE_DELETE set should be moved.
REFRESH_XP_HEADER_CACHE
A new list of message headers should be downloaded, and all message status marking flags should be cleared.
SUPPRESS_UI
Prevents the transport provider from displaying a user interface.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_BUSY
Another operation is in progress; it should be allowed to complete or it should be stopped before this operation is attempted.
MAPI_E_NO_SUPPORT
The remote transport provider involved does not support a user interface, and the client application should display the dialog box itself.
MAPI_E_USER_CANCEL
The user canceled the operation, typically by clicking the Cancel button in a dialog box.

Remarks

The MAPI spooler calls the IXPLogon::ValidateState method to support calls to the IMAPIStatus::ValidateState method for the status object. The transport provider should respond to the IXPLogon::ValidateState call exactly as if the MAPI spooler had opened a status object for the current logon session and then called ValidateState on that object.

To support its implementation of IMAPIStatus::ValidateState, the MAPI spooler calls IXPLogon::ValidateState on all logon objects for all active transport providers running in a profile session.

See Also

IMAPISession::MessageOptions, IMAPIStatus::ValidateState, IXPLogon::AddressTypes


IXPProvider : IUnknown

The IXPProvider interface is used to initialize a transport provider object and to shut down the object when it is no longer needed.

Quick Info

Header file: | MAPISPI.H
Exposed by: | Transport provider objects
Implemented by: | Transport providers
Called by: | The MAPI spooler
Interface identifier: | IID_IXPProvider
Pointer type: | LPXPROVIDER

Vtable Order

Shutdown | Closes down a transport provider in an orderly fashion.
TransportLogon | Establishes a session in which a client application logs on to a transport provider.


IXPProvider::Shutdown

The IXPProvider::Shutdown method closes down a transport provider in an orderly fashion.

Quick Info

See IXPProvider : IUnknown.

HRESULT Shutdown (
  ULONG FAR * lpulFlags
);

Parameters

lpulFlags
Reserved; must be zero.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

The MAPI spooler calls the IXPProvider::Shutdown method just prior to releasing a transport provider object. Before calling Shutdown, MAPI releases all logon objects for a provider.

See Also

XPProviderInit


IXPProvider::TransportLogon

The IXPProvider::TransportLogon method establishes a session in which a client application logs on to a transport provider.

Quick Info

See IXPProvider : IUnknown.

HRESULT TransportLogon(
  LPMAPISUP lpMAPISup,
  ULONG ulUIParam,
  LPTSTR lpszProfileName,
  ULONG FAR * lpulFlags,
  LPMAPIERROR FAR * lppMAPIError,
  LPXPLOGON FAR * lppXPLogon
);

Parameters

lpMAPISup
[in] Pointer to the transport provider's support object for callback functions within MAPI for this session. This object remains valid until the transport provider releases it.
ulUIParam
[in] Handle of the parent window for any dialog boxes or windows this method displays. The ulUIParam parameter can be non-null, for example when the LOGON_SETUP flag is set in the lpulFlags parameter.
lpszProfileName
[in] Pointer to the profile name of the user. The lpszProfileName parameter is used primarily when a dialog box must be presented.
lpulFlags
[in, out] Bitmask of flags that controls how the logon session is established. The following flags can be set on input by the MAPI spooler:
LOGON_NO_CONNECT
The user account is logging on to this transport provider for purposes other than transmission and reception of messages. The transport provider should not attempt to make any connections to other messaging systems.
LOGON_NO_DIALOG
No dialog box should be displayed even if the currently saved user credentials are invalid or insufficient for logon.
LOGON_NO_INBOUND
The transport provider does not need to initialize for reception of messages and should not accept incoming messages. The MAPI spooler can use the IXPLogon::TransportNotify method later on to signal the transport provider to enable inbound message processing.
LOGON_NO_OUTBOUND
The transport provider does not need to initialize for sending messages, as the MAPI spooler does not provide any. If a client application requires a connection to a remote provider during the composition of a message so that it can make IXPLogon::AddressTypes or IXPLogon::RegisterOptions method calls, the transport provider should make the connection. The MAPI spooler can use TransportNotify to signal the transport provider when outbound operations can begin.
MAPI_UNICODE
The passed-in string for the profile name is in Unicode format. If the MAPI_UNICODE flag is not set, the string is in ANSI format.

The following flags can be set on output by the transport provider:

LOGON_SP_IDLE
Requests that the MAPI spooler frequently call the transport provider's IXPLogon::Idle method for idle-time processing.
LOGON_SP_POLL
Requests that the MAPI spooler frequently call the IXPLogon::Poll method on the returned logon object to check for new messages. If this flag is not set, the MAPI spooler only checks for new messages when the transport provider uses the IMAPISupport::SpoolerNotify method to notify the spooler that there are new messages to process. A transport provider effectively becomes send-only by not setting this flag and by not notifying the MAPI spooler of message receipt.
LOGON_SP_RESOLVE
Requests that the MAPI spooler resolve to full addresses all message addresses for recipients not supported by this transport provider, so that the transport provider can construct a reply path for all recipients.
MAPI_UNICODE
The returned strings in the MAPIERROR structure, if any, are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppMAPIError
[out] Pointer to a pointer to the returned MAPIERROR structure, if any, containing version, component, and context information for the error. The lppMAPIError parameter can be set to NULL if there is no MAPIERROR structure to return.
lppXPLogon
[out] Pointer to the pointer to the returned transport provider logon object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_FAILONEPROVIDER
This provider cannot log on, but this error should not disable the service.
MAPI_E_UNCONFIGURED
The profile does not contain enough information for the logon to complete. MAPI calls the provider's message service entry point function.
MAPI_E_UNKNOWN_CPID
The provider cannot support the client's code page.
MAPI_E_UNKNOWN_LCID
The provider cannot support the client's locale information.
MAPI_E_USER_CANCEL
The user canceled the operation, typically by clicking the Cancel button in a dialog box.

Remarks

The MAPI spooler calls the IXPProvider::TransportLogon method to establish a logon session for a user.

Most transport providers use the IMAPISupport::OpenProfileSection method provided with the support object pointed to by the lpMAPISup parameter for saving and retrieving user identity information, server addresses, and credentials. Using OpenProfileSection enables a transport provider to save arbitrary information and associate it with a logon to a particular resource. For example, a provider can use OpenProfileSection to save the account name and password associated with a particular session and any server names or other necessary information needed to access resources for that session. MAPI hides information associated with a resource from outside access. The profile section made available through lpMAPISup is managed by the MAPI spooler so data related to this user context is separated from data for other contexts.

The transport provider must call the IUnknown::AddRef method on the support object and keep a copy of the pointer to this object as part of the provider logon object.

The profile display name in lpszProfileName is provided so the transport provider can use it in error messages or logon dialog boxes. If the provider retains this name, it must be copied to storage allocated by the provider.

Transport providers that are tightly coupled with other service providers may need to do additional work at logon to establish the proper credentials required for operations between companion providers.

Usually, transport providers are opened when the user first logs on to a profile. Because the first logon to a profile thus generally precedes logon to any message store, the MAPI spooler usually calls TransportLogon with both the LOGON_NO_INBOUND and LOGON_NO_OUTBOUND flags set in lpulFlags. Later, when the appropriate message stores are available in the profile session, the MAPI spooler calls TransportNotify to initiate inbound and outbound operations for the transport provider.

Passing the LOGON_NO_CONNECT flag in lpulFlags signals offline operation of the transport provider. This flag indicates no external connections should be made; if the transport provider cannot establish a session without an external connection, it should return an error value for the logon.

A transport provider should set the LOGON_SP_IDLE flag in lpulFlags at initialization time if it is designed to use time that the system otherwise spends idle. Such time is often used to handle automatic operations, such as automatic message downloading, timed message downloading, or timed message submission. If this flag is set, the MAPI spooler calls Idle when system idle time occurs to initiate such operations. The MAPI spooler does not call Idle at regular intervals; rather, it is called only during true idle time, so providers should not work on any assumption about how frequently their Idle methods will be called. Providers that support idle-time operations should supply a configuration user interface for it in their provider property sheet.

If the transport provider logon succeeds, the provider should return in the lppXPLogon parameter a pointer to a logon object. The MAPI spooler will use this object for further provider access. If TransportLogon displays a logon dialog box and the user cancels logon — typically by clicking the Cancel button in the dialog box — the provider should return MAPI_E_USER_CANCEL.

For most error values returned from TransportLogon, MAPI disables the message services to which the provider belongs. MAPI will not call any providers belonging to that service for the remainder of the MAPI session. In contrast, when TransportLogon returns the MAPI_E_FAILONEPROVIDER error value from its logon, MAPI does not disable the message service to which the provider belongs. TransportLogon should return MAPI_E_FAILONEPROVIDER if it encounters an error that does not warrant disabling the entire service for the remainder of the session.

If a provider returns MAPI_E_UNCONFIGURED from its logon, MAPI will call the provider's message service entry function and then retry the logon. MAPI passes MSG_SERVICE_CONFIGURE as the context, to give the service a chance to configure itself. If the client has chosen to allow a user interface on the logon, the service can present its configuration property sheet so the user can enter configuration information.

If the provider finds that all the required information is not in the profile, it should return MAPI_E_UNCONFIGURED so that MAPI calls the provider's message service entry point function.

See Also

IMAPISupport::OpenProfileSection, IMAPISupport::SpoolerNotify, IXPLogon::AddressTypes, IXPLogon::Idle, IXPLogon::Poll, IXPLogon::RegisterOptions, IXPLogon::TransportNotify, MAPIERROR


MAPI Functions and Related Macros

The following alphabetic entries contain documentation for the MAPI Functions.

The MAPI SDK contains functions and function prototypes that may not be supported in future versions of MAPI. Client applications and service providers can find alternate ways, if necessary, to implement the features supported by these functions.

To ensure the portability of your client or service provider code, do not use the following functions and function prototypes:

ChangeIdleRoutine | CloseIMsgSession
DeregisterIdleRoutine | EnableIdleRoutine
FBadColumnSet | FBadEntryList
FBadProp | FBadPropTag
FBadRestriction | FBadRglpNameID
FBadRglpszW | FBadRow
FBadRowSet | FBadSortOrderSet
FBinFromHex | FEqualNames
FNIDLE prototype | FPropCompareProp
FPropContainsProp | FPropExists
FtAddFt | FtgRegisterIdleRoutine
FtMulDw | FtMulDwDw
FtNegFt | FtSubFt
GetInstance | HexFromBin
HrAllocAdviseSink | HrComposeEID
HrComposeMsgID | HrDecomposeEID
HrDecomposeMsgID | HrEntryIDFromSz
HrGetOneProp | HrSetOneProp
HrSzFromEntryID | HrValidateIPMSubtree
LPropCompareProp | MAPIDeInitIdle
MAPIInitIdle | MapStorageSCode
NOTIFCALLBACK prototype | OpenIMsgSession
PpropFindProp | PropCopyMore
ScBinFromHexBounded | ScCopyNotifications
ScCopyProps | ScCountNotifications
ScCountProps | ScLocalPathFromUNC
ScRelocNotifications | ScRelocProps
ScUNCFromLocalPath | SzFindCh
SzFindLastCh | SzFindSz
UFromSz | UlAddRef
UlFromSzHex | UlPropSize
UlRelease |


ABProviderInit

The ABProviderInit function initializes an address book provider for operation.

Quick Info

Header file: | MAPISPI.H
Implemented by: | Address book providers
Called by: | MAPI

HRESULT ABProviderInit(
  HINSTANCE hInstance,
  LPMALLOC lpMalloc,
  LPALLOCATEBUFFER lpAllocateBuffer,
  LPALLOCATEMORE lpAllocateMore,
  LPFREEBUFFER lpFreeBuffer,
  ULONG ulFlags,
  ULONG ulMAPIVer,
  ULONG FAR * lpulProviderVer,
  LPABPROVIDER FAR * lppABProvider
);

Parameters

hInstance
[in] The instance of the address book provider's dynamic-link library (DLL) that MAPI used when it linked.
lpMalloc
[in] Pointer to a memory allocator object exposing the OLE IMalloc interface. The address book provider may need to use this allocation method when working with certain interfaces such as IStream.
lpAllocateBuffer
[in] Pointer to the MAPIAllocateBuffer function, to be used where required by MAPI to allocate memory.
lpAllocateMore
[in] Pointer to the MAPIAllocateMore function, to be used where required by MAPI to allocate additional memory.
lpFreeBuffer
[in] Pointer to the MAPIFreeBuffer function, to be used where required by MAPI to free memory.
ulFlags
[in] Bitmask of flags. The following flag can be set:
MAPI_NT_SERVICE
The provider is being loaded in the context of a Windows NT service, a special type of process without access to any user interface.
ulMAPIVer
[in] Version number of the service provider interface (SPI) that MAPI.DLL uses. For the current version number, see the MAPISPI.H header file.
lpulProviderVer
[out] Pointer to the version number of the SPI that this address book provider uses.
lppABProvider
[out] Pointer to a pointer to the initialized address book provider object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_VERSION
The SPI version being used by MAPI is not compatible with the SPI being used by this provider.

Remarks

MAPI calls the entry point function ABProviderInit to initialize an address book provider following a client logon.

Notes to Implementers

An address book provider must implement ABProviderInit as an entry point function in the provider's DLL. The implementation must be based on the ABPROVIDERINIT function prototype, also specified in MAPISPI.H. MAPI defines ABPROVIDERINIT to use the standard MAPI initialization call type, STDMAPIINITCALLTYPE, which causes ABProviderInit to follow the CDECL calling convention. An advantage of CDECL is that calls can be attempted even if the number of calling parameters does not match the number of defined parameters.

A provider can be initialized multiple times, as a result of appearing in several profiles in simultaneous use or of appearing more than once in the same profile. Because the provider object contains context, ABProviderInit must return a different provider object in lppABProvider for each initialization, even for multiple initializations in the same process.

The address book provider should use the functions pointed to by lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer for most memory allocation and deallocation. In particular, the provider must use these functions to allocate memory for use by client applications when calling object interfaces such as IMAPIProp::GetProps and IMAPITable::QueryRows. If the provider also expects to use the OLE memory allocator, it should call the IUnknown::AddRef method of the allocator object pointed to by the lpMalloc parameter.

For more information on writing ABProviderInit, see Implementing an Address Book Provider Entry Point Function. For more information on entry point functions, see Implementing a Service Provider Entry Point Function.

See Also

Provider Initialization Functions, HPProviderInit, IABProvider : IUnknown, MSProviderInit, XPProviderInit


ACCELERATEABSDI

The ACCELERATEABSDI function prototype defines a callback function to process accelerator keys in a modeless address book dialog box.

Quick Info

Header file: | MAPIDEFS.H
Defined function implemented by: | MAPI
Defined function called by: | Client applications

BOOL (STDMETHODCALLTYPE ACCELERATEABSDI)(
  ULONG ulUIParam,
  LPVOID lpvmsg
);

Parameters

ulUIParam
[in] An implementation-specific 32-bit value used for passing user interface information to a function. In applications running on Microsoft Windows, ulUIParam is the parent window handle for a dialog box and is of type HWND, cast to a ULONG. A value of zero indicates there is no parent window.
lpvmsg
[in] Pointer to a Windows message.

Return Values

A function with the ACCELERATEABSDI prototype returns TRUE if it handles the message.

Remarks

A function based on the ACCELERATEABSDI prototype is used only with a modeless dialog, that is, only if the client application has set the DIALOG_SDI flag in the ulFlags member of the ADRPARM structure.

A modeless dialog shares the client application's Windows message loop, instead of having its own loop. The application, which controls the message loop, does not know what accelerator keys the dialog uses, so it calls an ACCELERATEABSDI – based function to test for and act upon accelerator keys such as ctrl+p for printing.

A client's message loop calls the ACCELERATEABSDI – based function when the client invokes a modeless address book dialog box with the IAddrBook::Address method. This calling is terminated when MAPI calls a function based on the DISMISSMODELESS function prototype.


BuildDisplayTable

The BuildDisplayTable function creates a display table from the property page data contained in one or more DTPAGE structures.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Service providers

STDAPI BuildDisplayTable(
  LPALLOCATEBUFFER lpAllocateBuffer,
  LPALLOCATEMORE lpAllocateMore,
  LPFREEBUFFER lpFreeBuffer,
  LPMALLOC lpMalloc,
  HINSTANCE hInstance,
  UINT cPages,
  LPDTPAGE lpPage,
  ULONG ulFlags,
  LPMAPITABLE * lppTable,
  LPTABLEDATA * lppTblData
);

Parameters

lpAllocateBuffer
[in] Pointer to the MAPIAllocateBuffer function, to be used where required by MAPI to allocate memory.
lpAllocateMore
[in] Pointer to the MAPIAllocateMore function, to be used where required by MAPI to allocate additional memory.
lpFreeBuffer
[in] Pointer to the MAPIFreeBuffer function, to be used where required by MAPI to free memory.
lpMalloc
Unused; should be set to NULL.
hInstance
[in] An instance of a MAPI object from which BuildDisplayTable retrieves resources.
cPages
[in] Count of DTPAGE structures in the array pointed to by the lpPage parameter.
lpPage
[in] Pointer to an array of DTPAGE structures that contain information about the display table pages to be built.
ulFlags
[in] Bitmask of flags. The following flag can be set:
MAPI_UNICODE
The passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppTable
[out] Pointer to a pointer to the display table, which exposes the IMAPITable interface.
lppTblData
[in, out] Pointer to a pointer to a table data object exposing the ITableData interface on the table returned in the lppTable parameter. If no table data object is desired, lppTblData should be set to NULL instead of a pointer value.

Remarks

MAPI uses the functions pointed to by lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer for most memory allocation and deallocation, in particular to allocate memory for use by client applications when calling object interfaces such as IMAPIProp::GetProps and IMAPITable::QueryRows.

Notes to Callers

Everything possible is read from the dialog resource, including:

  • The page title — that is, the ulbLpszLabel member of the DTBLPAGE structure — read from the dialog title in the resource.
  • All control titles — that is, the ulbLpszLabel members of other control structures — read from the control text in the resource.

BuildDisplayTable overwrites anything passed in the input control structures with information from the dialog resource, which means the caller of BuildDisplayTable cannot dynamically specify page or control titles. Callers who need to do that can choose to have BuildDisplayTable return to them the table data object in lppTableData and change rows in it; but they might find it simpler to build the display table by hand in a table data object instead.

If lppTableData is not set to NULL, the provider is responsible for freeing the table data object when it is finished with the display table.


CALLERRELEASE

The CALLERRELEASE function prototype defines a callback function that can release a table data object when a table view is being released.

Quick Info

Header file: | MAPIUTIL.H
Defined function implemented by: | Client applications and service providers
Defined function called by: | MAPI

void CALLERRELEASE(
  ULONG ulCallerData,
  LPTABLEDATA lpTblData,
  LPMAPITABLE lpVue
);

Parameters

ulCallerData
[in] 32-bit caller data saved by MAPI with the table view and passed to the CALLERRELEASE – based callback function. The data provides context about the table view being released.
lpTblData
[in] Pointer to the ITableData : IUnknown interface for the table data object underlying the table view being released.
lpVue
[in] Pointer to the IMAPITable : IUnknown interface for the table view being released. This is an interface for the table object returned in the lppMAPITable parameter of the ITableData::HrGetView method that created the object to release.

Return Values

None

Remarks

A client application or service provider that has populated a table data object can call ITableData::HrGetView to create a read-only, sorted view of the table. The call to HrGetView passes a pointer to a CALLERRELEASE – based callback function and also a 32-bit context to be saved with the table view. When the reference count of the table view returns to zero and the view is being released, the IMAPITable implementation calls the callback function, passing the 32-bit context in the ulCallerData parameter.

A common use of a CALLERRELEASE based callback function is to release the underlying table data object and not have to keep track of it during subsequent processing.


ChangeIdleRoutine

The ChangeIdleRoutine function changes some or all of the characteristics of a FNIDLE – based idle routine.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

VOID ChangeIdleRoutine(
  FTG ftg,
  PFNIDLE pfnIdle,
  LPVOID pvIdleParam,
  short priIdle,
  ULONG csecIdle,
  USHORT iroIdle,
  USHORT ircIdle
);

Parameters

ftg
[in] Function tag that identifies the idle routine.
pfnIdle
[in] Pointer to the idle routine.
pvIdleParam
[in] Pointer to a new block of memory that the calling implementation allocates for the idle routine.
priIdle
[in] Value representing a new priority for the idle routine. Possible priorities for implementation-defined routines are greater than or less than zero, but not zero. A value of zero is reserved for a user event such as a mouse click or a WM_PAINT message.

Values greater than zero represent priorities for background tasks that have a higher priority than user events and are dispatched as part of the standard Windows message pump loop. Values less than zero represent priorities for idle tasks that only run during message-pump idle time. Examples of priorities are: 1 for foreground submission, –1 for power-edit character insertion, and –3 for downloading new messages.

csecIdle
[in] A new time, in hundredths of a second, to apply to the idle routine. The meaning of the initial time value varies, depending on what is passed in the iroIdle parameter. It can be:
  • The minimum period of user inaction that must elapse before the MAPI idle engine calls the idle routine for the first time, if the FIROWAIT flag is set in iroIdle. After this time passes, the idle engine can call the idle routine as often as necessary.
  • The minimum interval between calls to the idle routine, if the FIROINTERVAL flag is set in iroIdle.
iroIdle
[in] Bitmask of flags indicating new options for calling the idle routine. Exactly one of the following flags must be set:
FIROINTERVAL
The time specified by the csecIdle parameter is the minimum interval between successive calls to the idle routine.
FIROONCEONLY
Obsolete. Do not use.
FIROPERBLOCK
Obsolete. Do not use.
FIROWAIT
The time specified by the csecIdle parameter is the minimum period of user inaction that must elapse before the MAPI idle engine calls the idle routine for the first time. After this time passes, the idle engine can call the idle routine as often as necessary.
ircIdle
[in] Bitmask of flags used to indicate the changes to be made to the idle routine. The following flags can be set in any combination:
FIRCCSEC
A change to the time associated with the idle routine, that is, a change indicated by the value passed in the csecIdle parameter.
FIRCIRO
A change to the options for the idle routine, that is, a change indicated by the value passed in the iroIdle parameter.
FIRCPFN
A change to the idle routine pointer, that is, a change indicated by the value passed in the pfnIdle parameter.
FIRCPRI
A change to the priority of the idle routine, that is, a change indicated by the value passed in the priIdle parameter.
FIRCPV
A change to the memory block of the idle routine, that is, a change indicated by the value passed in the pvIdleParam parameter.

Remarks

The following functions deal with the MAPI idle engine and with idle routines based on the FNIDLE function prototype:

Idle routine function | Usage
ChangeIdleRoutine | Changes the characteristics of a registered idle routine.
DeregisterIdleRoutine | Removes a registered idle routine from the MAPI system.
EnableIdleRoutine | Disables or re-enables a registered idle routine without removing it from the MAPI system.
FtgRegisterIdleRoutine | Adds an idle routine to the MAPI system, with or without enabling it.
MAPIDeInitIdle | Shuts down the MAPI idle engine for the calling application.
MAPIInitIdle | Initializes the MAPI idle engine for the calling application.

ChangeIdleRoutine, DeregisterIdleRoutine, and EnableIdleRoutine take as an input parameter the function tag returned by FtgRegisterIdleRoutine.

When all foreground tasks for the platform become idle, the MAPI idle engine calls the highest priority idle routine that is ready to execute. There is no guarantee of calling order among idle routines of the same priority.

See Also

Idle Routine Functions


CheckParameters

The CheckParameters macro calls an internal function to validate debugging parameters on service provider methods called by MAPI.

Quick Info

Header file: | MAPIVAL.H
Implemented by: | MAPI
Called by: | Service providers

HRESULT CheckParameters(
  METHODS eMethod,
  LPVOID First
);

Parameters

eMethod
[in] Specifies, by enumeration, the method to validate.
First
[in] Pointer to the first argument on the stack.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

The CheckParameters macro has been superseded by the CheckParms macro. CheckParameters does not work correctly on RISC platforms and is now prevented from compiling on them. It still compiles and works correctly on Intel platforms, but CheckParms is recommended on all platforms.

See Also

Parameter Validation Macros


CheckParms

The CheckParms macro calls an internal function to validate debugging parameters on service provider methods called by MAPI.

Quick Info

Header file: | MAPIVAL.H
Implemented by: | MAPI
Called by: | Service providers

HRESULT CheckParms(
  METHODS eMethod,
  LPVOID First
);

Parameters

eMethod
[in] Specifies, by enumeration, the method to validate.
First
[in] Pointer to the first argument on the stack.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

In contrast to the ValidateParms and UlValidateParms macros, the CheckParms macro does not perform a full parameter validation. Parameters passed between MAPI and service providers are assumed to be correct, so CheckParms performs a debug validation only.

For more information on parameter validation, see Validating Parameters to Interface Methods.

See Also

Parameter Validation Macros


CloseIMsgSession

The CloseIMsgSession function closes a message session and all the messages created within that session.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | IMESSAGE.H
Implemented by: | MAPI
Called by: | Client applications and service providers

VOID CloseIMsgSession(
  LPMSGSESS lpMsgSess
);

Parameters

lpMsgSess
[in] Pointer to the message session object obtained using the OpenIMsgSession function at the start of the message session.

Remarks

A message session is used by client applications and service providers that want to deal with several related MAPI IMessage objects built on top of underlying OLE IStorage objects. The client or provider uses the OpenIMsgSession and CloseIMsgSession functions to wrap the creation of such messages inside a message session. Once the message session is opened, the client or provider passes a pointer to it in a call to OpenIMsgOnIStg to create a new IMessage-on-IStorage object.

A message session keeps track of all IMessage-on-IStorage objects opened during the duration of the session, in addition to all the attachments and other properties of the messages. When a client or provider calls CloseIMsgSession, it closes all these objects. Calling CloseIMsgSession is the only way to close IMessage-on-IStorage objects.

See Also

IMessage-On-IStorage Functions


CreateIProp

The CreateIProp function creates a property data object, that is, an IPropData object.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE CreateIProp(
  LPCIID lpInterface,
  ALLOCATEBUFFER FAR * lpAllocateBuffer,
  ALLOCATEMORE FAR * lpAllocateMore,
  FREEBUFFER FAR * lpFreeBuffer,
  LPVOID lpvReserved,
  LPPROPDATA FAR * lppPropData
);

Parameters

lpInterface
[in] Pointer to an interface identifier (IID) for the property data object. The valid interface identifier is IID_IMAPIPropData. Passing NULL in the lpInterface parameter also causes the property data object returned in the lppPropData parameter to be cast to the standard interface for a property data object.
lpAllocateBuffer
[in] Pointer to the MAPIAllocateBuffer function, to be used to allocate memory.
lpAllocateMore
[in] Pointer to the MAPIAllocateMore function, to be used to allocate additional memory where required.
lpFreeBuffer
[in] Pointer to the MAPIFreeBuffer function, to be used to free memory.
lpvReserved
Reserved; must be zero.
lppPropData
[out] Pointer to a pointer to the returned property data object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_INTERFACE_NOT_SUPPORTED
The requested interface is not supported for this object.

Remarks

The lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer input parameters point to the MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer functions, respectively. A client application calling CreateIProp passes in pointers to the MAPI functions just named; a service provider passes the pointers to these functions it received in its initialization call or retrieved with a call to the IMAPISupport::GetMemAllocRoutines method.

See Also

Properties Functions


CreateTable

The CreateTable function creates structures and an object handle for a table data object — an ITableData object — which can be used to create table contents.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE CreateTable(
  LPCIID lpInterface,
  ALLOCATEBUFFER FAR * lpAllocateBuffer,
  ALLOCATEMORE FAR * lpAllocateMore,
  FREEBUFFER FAR * lpFreeBuffer,
  LPVOID lpvReserved,
  ULONG ulTableType,
  ULONG ulPropTagIndexColumn,
  LPSPropTagArray lpSPropTagArrayColumns,
  LPTABLEDATA FAR * lppTableData
);

Parameters

lpInterface
[in] Pointer to an interface identifier (IID) for the table data object. The valid interface identifier is IID_IMAPITableData. Passing NULL in the lpInterface parameter also causes the table data object returned in the lppTableData parameter to be cast to the standard interface for a table data object.
lpAllocateBuffer
[in] Pointer to the MAPIAllocateBuffer function, to be used to allocate memory.
lpAllocateMore
[in] Pointer to the MAPIAllocateMore function, to be used to allocate additional memory where required.
lpFreeBuffer
[in] Pointer to the MAPIFreeBuffer function, to be used to free memory.
lpvReserved
Reserved; must be zero.
ulTableType
[in] A table type that is available to a client application or service provider as part of the IMAPITable::GetStatus return data on its table views. Possible values are:
TBLTYPE_DYNAMIC
The table's contents are dynamic and can change as the underlying data changes.
TBLTYPE_KEYSET
The rows within the table are fixed, but the values within these rows are dynamic and can change as the underlying data changes.
TBLTYPE_SNAPSHOT
The table is static and the contents do not change when the underlying data changes.
ulPropTagIndexColumn
[in] Index number of the column for use when changing table data.
lpSPropTagArrayColumns
[in] Pointer to an SPropTagArray structure containing an array of property tags indicating the properties required in the table for which the object holds data.
lppTableData
[out] Pointer to a pointer to the returned table data object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

The lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer input parameters point to the MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer functions, respectively. A client application calling CreateTable passes in pointers to the MAPI functions just named; a service provider passes the pointers to these functions that it received in its initialization call or retrieved with a call to the IMAPISupport::GetMemAllocRoutines method.

See Also

Table Functions, IMAPITable : IUnknown


DeinitMapiUtil

The DeinitMapiUtil function releases utility functions called explicitly by the ScInitMapiUtil function or implicitly by the MAPIInitialize function.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications

DeinitMapiUtil(VOID);

Parameters

None

Remarks

The ScInitMapiUtil and DeinitMapiUtil functions cooperate to call and release select utility functions, as opposed to the MAPIInitialize function, which calls core as well as utility functions. When ScInitMapiUtil calls utility functions, it also initializes the necessary memory.

When use of the functions called by ScInitMapiUtil is complete, DeinitMapiUtil must be explicitly called to release them. In contrast, MAPIUninitialize implicitly calls DeinitMapiUtil.


DeregisterIdleRoutine

The DeregisterIdleRoutine function removes a FNIDLE – based idle routine from the MAPI system.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

VOID DeregisterIdleRoutine(
  FTG ftg
);

Parameters

ftg
[in] Function tag that identifies the idle routine to be removed.

Remarks

The idle routine is deregistered when the DeregisterIdleRoutine call returns. Any task in a client application or service provider can deregister any idle routine for which it has a valid ftg parameter. In particular, an idle routine can deregister itself.

The following functions deal with the MAPI idle engine and with idle routines based on the FNIDLE function prototype:

Idle routine function | Usage
ChangeIdleRoutine | Changes the characteristics of a registered idle routine.
DeregisterIdleRoutine | Removes a registered idle routine from the MAPI system.
EnableIdleRoutine | Disables or re-enables a registered idle routine without removing it from the MAPI system.
FtgRegisterIdleRoutine | Adds an idle routine to the MAPI system, with or without enabling it.
MAPIDeInitIdle | Shuts down the MAPI idle engine for the calling application.
MAPIInitIdle | Initializes the MAPI idle engine for the calling application.

ChangeIdleRoutine, DeregisterIdleRoutine, and EnableIdleRoutine take as an input parameter the function tag returned by FtgRegisterIdleRoutine.

When all foreground tasks for the platform become idle, the MAPI idle engine calls the highest priority idle routine that is ready to execute. There is no guarantee of calling order among idle routines of the same priority.

After the idle routine is deregistered, the idle engine does not call it again. Any implementation that calls DeregisterIdleRoutine must deallocate any memory blocks to which it passed pointers for the idle engine to use in its original call to the FtgRegisterIdleRoutine function.

See Also

Idle Routine Functions


DISMISSMODELESS

The DISMISSMODELESS function prototype defines a callback function that MAPI calls when it has dismissed a modeless address book dialog box.

Quick Info

Header file: | MAPIDEFS.H
Defined function implemented by: | Client applications
Defined function called by: | MAPI

void (STDMETHODCALLTYPE DISMISSMODELESS)(
  ULONG ulUIParam,
  LPVOID lpvContext
);

Parameters

ulUIParam
[in] An implementation-specific 32-bit value typically used for passing user interface information to a function. For example, in Microsoft Windows this parameter is the parent window handle for the dialog box and is of type HWND, cast to a ULONG. A value of zero is always valid.
lpvContext
[in] Pointer to an arbitrary value passed to the callback function when MAPI calls it. This value can represent an address of significance to the client application. Typically, for C++ code, lpvContext is a pointer to the address of a C++ object.

Remarks

When the client application invokes a modeless address book dialog box, it includes in its Windows message loop a call to a function based on the ACCELERATEABSDI prototype, which checks for and processes accelerator keys. When the dialog box is closed, MAPI calls the DISMISSMODELESS based function so that the client application will stop calling the ACCELERATEABSDI based function.

See Also

ADRPARM


EnableIdleRoutine

The EnableIdleRoutine function enables or disables a FNIDLE – based idle routine.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

VOID EnableIdleRoutine(
  FTG ftg,
  BOOL fEnable
);

Parameters

ftg
[in] Function tag that identifies the idle routine to be enabled or disabled.
fEnable
[in] Contains TRUE if the idle engine should enable the idle routine, or FALSE if it should disable it.

Remarks

The following functions deal with the MAPI idle engine and with idle routines based on the FNIDLE function prototype:

Idle routine function | Usage
ChangeIdleRoutine | Changes the characteristics of a registered idle routine.
DeregisterIdleRoutine | Removes a registered idle routine from the MAPI system.
EnableIdleRoutine | Disables or re-enables a registered idle routine without removing it from the MAPI system.
FtgRegisterIdleRoutine | Adds an idle routine to the MAPI system, with or without enabling it.
MAPIDeInitIdle | Shuts down the MAPI idle engine for the calling application.
MAPIInitIdle | Initializes the MAPI idle engine for the calling application.

ChangeIdleRoutine, DeregisterIdleRoutine, and EnableIdleRoutine take as an input parameter the function tag returned by FtgRegisterIdleRoutine.

When all foreground tasks for the platform become idle, the MAPI idle engine calls the highest priority idle routine that is ready to execute. There is no guarantee of calling order among idle routines of the same priority.

See Also

Idle Routine Functions


FBadColumnSet

The FBadColumnSet function tests the validity of a table column set for use by a service provider in a subsequent call to the IMAPITable::SetColumns method.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIVAL.H
Implemented by: | MAPI
Called by: | Service providers

ULONG FBadColumnSet(
  LPSPropTagArray lpptaCols
);

Parameters

lpptaCols
[in] Pointer to an SPropTagArray structure containing an array of property tags defining the table columns to validate.

Return Values

TRUE
The specified column set is invalid.
FALSE
The specified column set is valid.

Remarks

The FBadColumnSet function treats columns of type PT_ERROR as invalid and columns of type PT_NULL as valid.

See Also

Structure Validation Functions


FBadEntryList

The FBadEntryList function validates a list of MAPI entry identifiers.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIVAL.H
Implemented by: | MAPI
Called by: | Service providers

BOOL FBadEntryList(
  LPENTRYLIST lpEntryList
);

Parameters

lpEntryList
[in] Pointer to an ENTRYLIST structure containing an array of entry identifiers to be validated.

Return Values

TRUE
One or more of the listed entry identifiers are invalid.
FALSE
All of the listed entry identifiers are valid.

Remarks

The FBadEntryList function determines if the entry identifier list has been correctly generated. An example of an invalid identifier is one for which memory has been incorrectly allocated or an identifier of an incorrect size.

See Also

Structure Validation Functions


FBadProp

The FBadProp function validates a specified property.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIVAL.H
Implemented by: | MAPI
Called by: | Service providers

ULONG FBadProp(
  LPSPropValue lpprop
);

Parameters

lpprop
[in] An SPropValue structure defining the property to be validated.

Return Values

TRUE
The specified property is invalid.
FALSE
The specified property is valid.

Remarks

A service provider can call the FBadProp function for several reasons, for example to prepare for a call to the IMAPIProp::SetProps method setting a property. FBadProp validates the specified property depending on the property type. For example, if the property is Boolean, FBadProp ensures that its value is either TRUE or FALSE. If the property is binary, FBadProp checks its pointer and size and makes sure that it is allocated correctly.

See Also

Structure Validation Functions, FBadPropTag


FBadPropTag

The FBadPropTag function validates a specified property tag.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIVAL.H
Implemented by: | MAPI
Called by: | Service providers

ULONG FBadPropTag(
  ULONG ulPropTag
);

Parameters

ulPropTag
[in] The property tag to be validated.

Return Values

TRUE
The specified property tag is not a valid MAPI property tag.
FALSE
The specified property tag is a valid MAPI property tag.

Remarks

The FBadPropTag function validates the specified property tag based on MAPI definitions. It ensures that the property type is one of the types defined by MAPI and that the property identifier is defined to be of that type.

See Also

Structure Validation Functions, FBadProp


FBadRestriction

The FBadRestriction function validates a restriction used to limit a table view.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIVAL.H
Implemented by: | MAPI
Called by: | Service providers

ULONG FBadRestriction(
  LPSRestriction lpres
);

Parameters

lpres
[in] An SRestriction structure defining the restriction to be validated.

Return Values

TRUE
The specified restriction, or one or more of its subrestrictions, is invalid.
FALSE
The specified restriction and all its subrestrictions are valid.

Remarks

Once a restriction is validated, it can be passed in calls to the IMAPITable::Restrict method to restrict the table to certain rows, to the IMAPITable::FindRow method to locate a table row, and to methods of the IMAPIContainer interface to perform a restriction on a container object.

See Also

Structure Validation Functions


FBadRglpNameID

The FBadRglpNameID function validates an array of structures that describe named properties and verifies their allocation.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIVAL.H
Implemented by: | MAPI
Called by: | Service providers

BOOL FBadRglpNameID(
  LPMAPINAMEID FAR * lppNameId,
  ULONG cNames
);

Parameters

lppNameId
[in] Pointer to an array of MAPINAMEID structures describing the named properties.
cNames
[in] Count of named property structures in the array pointed to by the lppNameId parameter.

Return Values

TRUE
One or more of the specified property name structures is invalid.
FALSE
The specified property name structures are all valid.

Remarks

The FBadRglpNameID function can be used when setting up for a call to IMAPIProp::GetIDsFromNames or IMAPIProp::GetNamesFromIDs.

See Also

Structure Validation Functions


FBadRglpszW

The FBadRglpszW function validates all strings in an array of Unicode strings.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIVAL.H
Implemented by: | MAPI
Called by: | Service providers

BOOL FBadRglpszW(
  LPWSTR FAR * lppszW,
  ULONG cStrings
);

Parameters

lppszW
[in] Pointer to an array of null-terminated Unicode strings.
cStrings
[in] Count of strings in the array pointed to by the lppszW parameter.

Return Values

TRUE
One or more of the strings in the specified array are invalid.
FALSE
The strings in the specified array are valid.

See Also

Structure Validation Functions


FBadRow

The FBadRow function validates a row in a table.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIVAL.H
Implemented by: | MAPI
Called by: | Service providers

ULONG FBadRow(
  LPSRow lprow
);

Parameter

lprow
[in] Pointer to an SRow structure identifying the row to be validated.

Return Values

TRUE
The specified row is invalid.
FALSE
The specified row is valid.

See Also

Structure Validation Functions, FBadRowSet


FBadRowSet

The FBadRowSet function validates all table rows included in a set of table rows.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIVAL.H
Implemented by: | MAPI
Called by: | Service providers

BOOL FBadRowSet(
  LPSRowSet lpRowSet
);

Parameter

lpRowSet
[in] Pointer to an SRowSet structure identifying the row set to be validated. If the pointer is NULL, the structure is invalid.

Return Values

TRUE
A row of the specified row set is invalid, or the row set itself is invalid.
FALSE
The rows of the specified row set and the row set itself are all valid.

See Also

Structure Validation Functions, FBadRow


FBadSortOrderSet

The FBadSortOrderSet function validates a sort order set by verifying its memory allocation.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIVAL.H
Implemented by: | MAPI
Called by: | Service providers

ULONG FBadSortOrderSet(
  LPSSortOrderSet lpsos
);

Parameter

lpsos
[in] Pointer to an SSortOrderSet structure identifying the sort order set to be validated.

Return Values

TRUE
The specified sort order set is invalid.
FALSE
The specified sort order set is valid.

Remarks

The FBadSortOrderSet function can be used to prepare for a call to a sort method such as the IMAPITable::SortTable method.

See Also

Structure Validation Functions


FBinFromHex

The FBinFromHex function converts a string representation of a hexadecimal number to binary data.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

BOOL FBinFromHex(
  LPTSTR sz,
  LPBYTE pb
);

Parameters

sz
[in] Pointer to the null-terminated string to be converted. Valid characters include the hexadecimal characters zero through nine and both uppercase and lowercase characters A through F.
pb
[out] Pointer to the returned binary number.

Return Values

TRUE
The string was successfully converted into a binary number.
FALSE
The input string contains invalid ASCII hexadecimal characters.

See Also

String Operation Functions, ScBinFromHexBounded


FEqualNames

The FEqualNames function determines whether two MAPI named properties are the same.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

BOOL FEqualNames(
  LPMAPINAMEID lpName1,
  LPMAPINAMEID lpName2
);

Parameters

lpName1
[in] Pointer to a MAPINAMEID structure describing the first named property.
lpName2
[in] Pointer to a MAPINAMEID structure describing the second named property.

Return Values

TRUE
The two property names are equal.
FALSE
The two property names are not equal.

Remarks

The FEqualNames function is useful because the MAPINAMEID structure contains a GUID and can represent the property name itself in more than one way. This means the two structures cannot be compared by simple binary methods.

The testing process is case-sensitive for the property name strings.

See Also

Properties Functions


FNIDLE

The FNIDLE function prototype defines an idle routine that the MAPI idle engine calls periodically according to priority.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Defined function implemented by: | Client applications and service providers
Defined function called by: | MAPI
Corresponding pointer type: | PFNIDLE

BOOL (STDAPICALLTYPE FNIDLE)(
  LPVOID lpvContext
);

Parameters

lpvContext
[in] Pointer to a block of memory that MAPI passes to the idle routine each time it calls it. This pointer is passed to the MAPI idle engine in the pvIdleParam parameter by FtgRegisterIdleRoutine. The data in the memory block can provide context for the call to the idle routine, such as which object to operate on, or the current state of a lengthy operation.

Return Values

FALSE
An idle routine with the FNIDLE prototype should always return FALSE.

Remarks

The specific functionality of the idle routine is determined by the implementing client application or service provider.

The client or provider must limit the execution time of each state of an idle routine. Every state should perform a minimum amount of coherent processing, update the current state in the context data pointed to by lpvContext, and return to the MAPI idle engine.

The client or provider must call the MAPI function MAPIInitIdle before it can register its own idle routine with a call to the FtgRegisterIdleRoutine function.

The following functions deal with the MAPI idle engine and with idle routines based on the FNIDLE function prototype:

Idle routine function | Usage
ChangeIdleRoutine | Changes the characteristics of a registered idle routine.
DeregisterIdleRoutine | Removes a registered idle routine from the MAPI system.
EnableIdleRoutine | Disables or re-enables a registered idle routine without removing it from the MAPI system.
FtgRegisterIdleRoutine | Adds an idle routine to the MAPI system, with or without enabling it.
MAPIDeInitIdle | Shuts down the MAPI idle engine for the calling application.
MAPIInitIdle | Initializes the MAPI idle engine for the calling application.

ChangeIdleRoutine, DeregisterIdleRoutine, and EnableIdleRoutine take as an input parameter the function tag returned by FtgRegisterIdleRoutine.

When all foreground tasks for the platform become idle, the MAPI idle engine calls the highest priority idle routine that is ready to execute. There is no guarantee of calling order among idle routines of the same priority.

See Also

Idle Routine Functions


FPropCompareProp

The FPropCompareProp function compares two property values using a binary relational operator.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

BOOL FPropCompareProp(
  LPSPropValue lpSPropValue1,
  ULONG ulRelOp,
  LPSPropValue lpSPropValue2
);

Parameters

lpSPropValue1
[in] Pointer to an SPropValue structure defining the first property value for comparison.
ulRelOp
[in] The relational operator to use in the comparison.
lpSPropValue2
[in] Pointer to an SPropValue structure defining the second property value for comparison.

Return Values

TRUE
The property values satisfy the specified relation.
FALSE
The property values do not satisfy the specified relation.

Remarks

The comparison method depends on the property types specified in the SPropValue property definitions. The FPropCompareProp and FPropContainsProp functions can be used to prepare restrictions for generating a table.

The order of comparison is lpSPropValue1, ulRelOp, lpSPropValue2. If the property types of the property values to be compared do not match, the FPropCompareProp function returns FALSE. For allowable values for ulRelOp and for more information on property comparison, see the SComparePropsRestriction structure.

See Also

Properties Functions


FPropContainsProp

The FPropContainsProp function compares two property values, generally strings or binary arrays, to see if one contains the other.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

BOOL FPropContainsProp(
  LPSPropValue lpSPropValueDst,
  LPSPropValue lpSPropValueSrc,
  ULONG ulFuzzyLevel
);

Parameters

lpSPropValueDst
[in] Pointer to an SPropValue structure defining the property value that might contain the search string pointed to by the lpSPropValueSrc parameter.
lpSPropValueSrc
[in] Pointer to an SPropValue structure defining the search string that FPropContainsProp is seeking within the property value pointed to by the lpSPropValueDst parameter.
ulFuzzyLevel
[in] Option settings defining the level of preciseness to use in the comparison. The lower 16 bits apply to properties of type PT_BINARY and PT_STRING8. They must be set to exactly one of the following values:
FL_FULLSTRING
The lpSPropValueSrc search string must be equal to the property value identified by lpSPropValueDst.
FL_PREFIX
The lpSPropValueSrc search string must appear at the beginning of the property value identified by lpSPropValueDst. The two values should be compared only up to the length of the search string indicated by lpSPropValueSrc.
FL_SUBSTRING
The lpSPropValueSrc search string must be contained anywhere within the property value identified by lpSPropValueDst.

The upper 16 bits apply only to properties of type PT_STRING8. They can be set to the following values in any combination:

FL_IGNORECASE
The comparison should be made without considering case sensitivity.
FL_IGNORENONSPACE
The comparison should ignore Unicode-defined nonspacing characters such as diacritical marks.
FL_LOOSE
The comparison should result in a match whenever possible, ignoring case sensitivity and nonspacing characters.

Return Values

TRUE
The parameters are all valid and the lpSPropValueSrc search string is contained as specified in the lpSPropValueDst property value.
FALSE
The property values being compared are not of type PT_STRING8 or PT_BINARY, the property values are of different types, or the lpSPropValueSrc search string is not contained as specified in the lpSPropValueDst property value.

Remarks

The comparison method depends on the property types specified in the SPropValue property definitions and the fuzzy level heuristic provided in the ulFuzzyLevel parameter. The FPropCompareProp and FPropContainsProp functions can be used to prepare restrictions for generating a table.

The upper 16 bits of ulFuzzyLevel are ignored for property type PT_BINARY. If the settings in ulFuzzyLevel are missing or invalid, a full-string exact match is performed. For more information on property containment, see the SContentRestriction structure.

See Also

Properties Functions


FPropExists

The FPropExists function searches for a given property tag in an IMAPIProp interface or an interface derived from IMAPIProp, such as IMessage or IMAPIFolder.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

BOOL FPropExists(
  LPMAPIPROP pobj,
  ULONG ulPropTag
);

Parameters

pobj
[in] Pointer to the IMAPIProp interface or interface derived from IMAPIProp within which to search for the property tag.
ulPropTag
[in] Property tag for which to search.

Return Values

TRUE
A match for the given property tag was found.
FALSE
A match for the given property tag was not found.

Remarks

If the property tag in the ulPropTag parameter has type PT_UNSPECIFIED, the FPropExists function looks for a match based only on the property identifier. Otherwise, the match is for the entire property tag, including the type.

See Also

Properties Functions


FreePadrlist

The FreePadrlist function destroys an ADRLIST structure and frees associated memory, including memory allocated for all member arrays and structures.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

void FreePadrlist(
  LPADRLIST padrlist
);

Parameter

padrlist
[in] Pointer to the ADRLIST structure to be destroyed.

Notes to Callers

As part of its implementation of FreePadrlist, MAPI calls the MAPIFreeBuffer function to free every entry in the ADRLIST structure before freeing the complete structure. Therefore all such entries must have followed the allocation rules for the ADRLIST structure, using an individual MAPIAllocateBuffer call for each member array and structure.

For more information on allocating memory for ADRLIST and SRowSet structures, see Managing Memory for ADRLIST and SRowSet Structures.

See Also

Memory Management Functions


FreeProws

The FreeProws function destroys an SRowSet structure and frees associated memory, including memory allocated for all member arrays and structures.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

void FreeProws(
  LPSRowSet prows
);

Parameter

prows
[in] Pointer to the SRowSet structure to be destroyed.

Notes to Callers

As part of its implementation of FreeProws, MAPI calls the MAPIFreeBuffer function to free every entry in the SRowSet structure before freeing the complete structure. Therefore all such entries must have followed the allocation rules for the SRowSet structure, using an individual MAPIAllocateBuffer call for each member array and structure.

For more information on allocating memory for ADRLIST and SRowSet structures, see Managing Memory for ADRLIST and SRowSet Structures.

See Also

Table Functions


FtAddFt

The FtAddFt function adds one unsigned 64-bit integer to another.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

FILETIME FtAddFt(
  FILETIME Addend1,
  FILETIME Addend2
);

Parameters

Addend1
[in] A FILETIME structure containing the first unsigned 64-bit integer to be added.
Addend2
[in] A FILETIME structure containing the second unsigned 64-bit integer to be added.

Remarks

The FtAddFt function returns a FILETIME structure containing the sum of the two integers. The two input parameters remain unchanged.

See Also

Large Integer Functions


FtgRegisterIdleRoutine

The FtgRegisterIdleRoutine function adds a FNIDLE – based idle routine to the MAPI system.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

FTG FtgRegisterIdleRoutine(
  PFNIDLE pfnIdle,
  LPVOID pvIdleParam,
  short priIdle,
  ULONG csecIdle,
  USHORT iroIdle
);

Parameters

pfnIdle
[in] Pointer to the idle routine.
pvIdleParam
[in] Pointer to a block of memory that the idle engine should pass as a parameter to the idle routine when it calls it.
priIdle
[in] Initial priority for the idle routine. Possible priorities for implementation-defined routines are greater than or less than zero, but not zero. The zero priority is reserved for a user event such as a mouse click or a WM_PAINT message.

Priorities greater than zero represent background tasks that have a higher priority than user events and are dispatched as part of the standard Windows message pump loop. Priorities less than zero represent idle tasks that only run during message pump idle time. Examples of priorities are: 1 for foreground submission, –1 for power-edit character insertion, and –3 for downloading new messages.

csecIdle
[in] Initial time value, in hundredths of a second, to be used in specifying idle routine parameters. The meaning of the initial time value varies, depending on what is passed in the iroIdle parameter. It can be:
  • The minimum period of user inaction that must elapse before the MAPI idle engine calls the idle routine for the first time, if the FIROWAIT flag is set in iroIdle. After this time passes, the idle engine can call the idle routine as often as necessary.
  • The minimum interval between calls to the idle routine, if the FIROINTERVAL flag is set in iroIdle.
iroIdle
[in] Bitmask of flags used to set initial options for the idle routine. Exactly one of the following flags must be set:
FIRODISABLED
The idle routine is to be initially disabled when registered. The default action is to enable the idle routine when FtgRegisterIdleRoutine registers it.
FIROINTERVAL
The time specified by the csecIdle parameter is the minimum interval between successive calls to the idle routine.
FIROONCEONLY
Obsolete. Do not use.
FIROPERBLOCK
Obsolete. Do not use.
FIROWAIT
The time specified by the csecIdle parameter is the minimum period of user inaction that must elapse before the MAPI idle engine calls the idle routine for the first time. After this time passes, the idle engine can call the idle routine as often as necessary.

Remarks

The FtgRegisterIdleRoutine function returns a function tag identifying the idle routine that has been added to the MAPI system. If FtgRegisterIdleRoutine cannot register the idle routine for the client application or service provider — for example, because of memory problems — it returns NULL.

The following functions deal with the MAPI idle engine and with idle routines based on the FNIDLE function prototype:

Idle routine function | Usage
ChangeIdleRoutine | Changes the characteristics of a registered idle routine.
DeregisterIdleRoutine | Removes a registered idle routine from the MAPI system.
EnableIdleRoutine | Disables or re-enables a registered idle routine without removing it from the MAPI system.
FtgRegisterIdleRoutine | Adds an idle routine to the MAPI system, with or without enabling it.
MAPIDeInitIdle | Shuts down the MAPI idle engine for the calling application.
MAPIInitIdle | Initializes the MAPI idle engine for the calling application.

ChangeIdleRoutine, DeregisterIdleRoutine, and EnableIdleRoutine take as an input parameter the function tag returned by FtgRegisterIdleRoutine.

When all foreground tasks for the platform become idle, the MAPI idle engine calls the highest priority idle routine that is ready to execute. There is no guarantee of calling order among idle routines of the same priority.

See Also

Idle Routine Functions


FtMulDw

The FtMulDw function multiplies an unsigned 64-bit integer by an unsigned 32-bit integer.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

FILETIME FtMulDw(
  DWORD Multiplier,
  FILETIME Multiplicand
);

Parameters

Multiplier
[in] A double word containing the unsigned 32-bit integer multiplier.
Multiplicand
[in] A FILETIME structure containing the unsigned 64-bit integer to be multiplied by the value in the Multiplier parameter.

Remarks

The FtMulDw function returns a FILETIME structure containing the product of the two integers. The two input parameters remain unchanged.

See Also

Large Integer Functions


FtMulDwDw

The FtMulDwDw function multiplies one unsigned 32-bit integer by another.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

FILETIME FtMulDwDw(
  DWORD Multiplicand,
  DWORD Multiplier
);

Parameters

Multiplicand
[in] A double word containing the unsigned 32-bit integer to be multiplied by the value in the Multiplier parameter.
Multiplier
[in] A double word containing the unsigned 32-bit integer multiplier.

Remarks

The FtMulDwDw function returns a FILETIME structure containing the product of the two integers. The two input parameters remain unchanged.

See Also

Large Integer Functions


FtNegFt

The FtNegFt function computes the two's complement of an unsigned 64-bit integer.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

FILETIME FtNegFt(
  FILETIME ft
);

Parameters

ft
[in] A FILETIME structure containing the unsigned 64-bit integer for which to compute the two's complement.

Remarks

The FtNegFt function returns a FILETIME structure containing the two's complement of the integer. The input parameter remains unchanged.

See Also

Large Integer Functions


FtSubFt

The FtSubFt function subtracts one unsigned 64-bit integer from another.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

FILETIME FtSubFt(
  FILETIME Minuend,
  FILETIME Subtrahend
);

Parameters

Minuend
[in] A FILETIME structure containing the unsigned 64-bit integer from which the value in the Subtrahend parameter is to be subtracted.
Subtrahend
[in] A FILETIME structure containing the unsigned 64-bit integer that is subtracted from the value indicated by the Minuend parameter.

Remarks

The FtSubFt function returns a FILETIME structure containing the result of the subtraction. The two input parameters remain unchanged.

See Also

Large Integer Functions


GetAttribIMsgOnIStg

The GetAttribIMsgOnIStg function retrieves attributes of properties on an IMessage object supplied by the OpenIMsgOnIStg function.

Quick Info

Header file: | IMESSAGE.H
Implemented by: | MAPI
Called by: | Client applications and message store providers

HRESULT GetAttribIMsgOnIStg(
  LPVOID lpObject,
  LPSPropTagArray lpPropTagArray,
  LPSPropAttrArray FAR * lppPropAttrArray
);

Parameters

lpObject
[in] Pointer to an IMessage object obtained from the OpenIMsgOnIStg function.
lpPropTagArray
[in] Pointer to an SPropTagArray structure containing an array of property tags indicating the properties for which attributes are to be retrieved.
lppPropAttrArray
[out] Pointer to a pointer to the returned SPropAttrArray structure containing the retrieved property attributes.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_W_ERRORS_RETURNED
The call succeeded overall, but one or more properties could not be accessed and were returned with a property type of PT_ERROR.

Remarks

Property attributes can only be accessed on property objects, that is, objects implementing the IMAPIProp : IUnknown interface. To make MAPI properties available on an OLE structured storage object, OpenIMsgOnIStg builds an IMessage : IMAPIProp object on top of the OLE IStorage object. The property attributes on such objects can be set or altered with SetAttribIMsgOnIStg and retrieved with GetAttribIMsgOnIStg.

Note GetAttribIMsgOnIStg and SetAttribIMsgOnIStg do not operate on all IMessage objects. They are only valid for IMessage-on-IStorage objects returned by OpenIMsgOnIStg.

The number and positions of the attributes in the lppPropAttrArray parameter correspond to the number and positions of the property tags in the lpPropTagArray parameter.

See Also

IMessage-On-IStorage Functions


GetInstance

The GetInstance function copies one value within a multivalued property to a single-valued property of the same type.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

VOID GetInstance(
  LPSPropValue pvalMv,
  LPSPropValue pvalSv,
  ULONG uliInst
);

Parameters

pvalMv
[in] Pointer to an SPropValue structure defining a multivalued property.
pvalSv
[in] Pointer to a single-valued property to receive data.
uliInst
[in] The instance number, that is, the array element, of the value being copied from the structure indicated by the pvalMv parameter.

Remarks

If the value copied is too large for the allocated memory, the GetInstance function only copies pointers rather than allocating new memory.

See Also

Properties Functions


HexFromBin

The HexFromBin function converts a binary number into a string representation of a hexadecimal number.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

void HexFromBin(
  LPBYTE pb,
  int cb,
  LPTSTR sz
);

Parameters

pb
[in] Pointer to the binary data to be converted.
cb
[in] Size, in bytes, of the binary data pointed to by the pb parameter.
sz
[out] Pointer to a null-terminated ASCII string representing the binary data in hexadecimal digits.

Remarks

The HexFromBin function takes a pointer to a unit of binary data whose size is indicated by the cb parameter. It returns in the sz string, within (2*cb)+1 bytes of memory, a representation of this binary information in hexadecimal numbers. If the byte value is decimal 10, for example, the hexadecimal string will be 0A, so one byte converts to two bytes in the string.

See Also

String Operation Functions


HPProviderInit

The HPProviderInit function initializes a messaging hook provider for operation.

Quick Info

Header file: | MAPIHOOK.H
Implemented by: | Messaging hook providers
Called by: | MAPI

HRESULT HPProviderInit(
  LPMAPISESSION lpSession,
  HINSTANCE hInstance,
  LPALLOCATEBUFFER lpAllocateBuffer,
  LPALLOCATEMORE lpAllocateMore,
  LPFREEBUFFER lpFreeBuffer,
  LPMAPIUID lpSectionUID,
  ULONG ulFlags,
  LPSPOOLERHOOK FAR * lppSpoolerHook
);

Parameters

lpSession
[in] Pointer to the object representing the MAPI spooler session. Because the messaging hook provider runs in the spooler session, all its components must be trusted code, that is, thoroughly debugged code that does not fail or compromise the spooler's operation. The messaging hook provider should call the IUnknown::AddRef method on the session object.
hInstance
[in] The instance of the messaging hook provider's dynamic-link library (DLL) that MAPI used when it linked.
lpAllocateBuffer
[in] Pointer to the MAPIAllocateBuffer function, to be used where required by MAPI to allocate memory.
lpAllocateMore
[in] Pointer to the MAPIAllocateMore function, to be used where required by MAPI to allocate additional memory.
lpFreeBuffer
[in] Pointer to the MAPIFreeBuffer function, to be used where required by MAPI to free memory.
lpSectionUID
[in] Pointer to the MAPIUID of the messaging hook provider's profile section. HPProviderInit can open this identifier using a session-level call to the IMAPISupport::OpenProfileSection method. However, because MAPI and the MAPI spooler control some properties in the session, the provider should use the range of provider-specific property identifiers for storage and retrieval of profile section properties.
ulFlags
[in] Bitmask of flags used to control whether the messaging hook provider is called for incoming or outgoing messages. The following flags can be set:
HOOK_INBOUND
The messaging hook provider processes messages inbound to the MAPI spooler.
HOOK_OUTBOUND
The messaging hook provider processes messages outbound from the MAPI spooler.
MAPI_NT_SERVICE
The provider is being loaded in the context of a Windows NT service, a special type of process without access to any user interface.
lppSpoolerHook
[out] Pointer to a pointer to the initialized messaging hook provider object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

MAPI calls the entry point function HPProviderInit to initialize a messaging hook provider following a client logon. HPProviderInit is called once for each messaging hook provider specified in the client's profile.

Notes to Implementers

A messaging hook provider must implement HPProviderInit as an entry point function in the provider's DLL. The implementation must be based on the HPPROVIDERINIT function prototype, also specified in MAPIHOOK.H. MAPI defines HPPROVIDERINIT to use the standard MAPI initialization call type, STDMAPIINITCALLTYPE, which causes HPProviderInit to follow the CDECL calling convention. An advantage of CDECL is that calls can be attempted even if the number of calling parameters does not match the number of defined parameters.

A provider can be initialized multiple times as a result of appearing in several profiles in simultaneous use or of appearing more than once in the same profile. Because the provider object contains context, HPProviderInit must return a different provider object in lppSpoolerHook for each initialization, even for multiple initializations in the same process.

The messaging hook provider should use the functions pointed to by lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer for most memory allocation and deallocation. In particular, the provider must use these functions to allocate memory for use by client applications when calling object interfaces such as IMAPIProp::GetProps and IMAPITable::QueryRows.

If the provider needs to use mutex objects or critical sections, it should set them up during initialization using HPProviderInit. A mutex object should be owned by the message-hook provider object created by this function.

For more information on writing HPProviderInit, see Implementing HPProviderInit for Hook Providers. For more information on entry point functions, see Implementing a Service Provider Entry Point Function.

See Also

Provider Initialization Functions, ABProviderInit, IMAPISession : IUnknown, MSProviderInit, XPProviderInit


HrAddColumnsEx

The HrAddColumnsEx function adds or moves columns to the beginning of an existing table.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

HRESULT HrAddColumnsEx(
  LPMAPITABLE lptbl,
  LPSPropTagArray lpproptagColumnsNew,
  LPALLOCATEBUFFER lpAllocateBuffer,
  LPFREEBUFFER lpFreeBuffer,
  void (FAR * lpfnFilterColumns) (LPSPropTagArray ptaga)
);

Parameters

lptbl
[in] Pointer to the MAPI table affected.
lpproptagColumnsNew
[in] Pointer to an SPropTagArray structure containing an array of property tags for the properties to be added or moved to the beginning of the table.
lpAllocateBuffer
[in] Pointer to the MAPIAllocateBuffer function, to be used to allocate memory.
lpFreeBuffer
[in] Pointer to the MAPIFreeBuffer function, to be used to free memory.
lpfnFilterColumns
[in] Pointer to a callback function furnished by the caller. If the lpfnFilterColumns parameter is set to NULL, no callback is made.
ptaga
[in] Pointer to an SPropTagArray structure containing the array of property tags already existing in the table before properties are added or moved to the beginning. HrAddColumnsEx passes this pointer as the parameter to the callback function pointed to by lpfnFilterColumns.

Return Values

S_OK
The call succeeded and the specified columns were moved or added.

Remarks

The properties passed to HrAddColumnsEx using the lpproptagColumnsNew parameter become the first properties exposed on subsequent calls to the IMAPITable::QueryRows method. Any properties previously in the table that were not specified in the lpproptagColumnsNew parameter are exposed after all the added and moved properties.

If any table properties are undefined when QueryRows is called, they are returned with property type PT_NULL and property identifier PROP_ID_NULL.

Notes to Callers

The HrAddColumnsEx function allows the caller to furnish a callback function to filter the columns that were already in the table, for example to convert strings from property type PT_UNICODE to PT_STRING8. HrAddColumnsEx passes a pointer to the previously existing column set as the parameter to the callback function. The callback function can change data within the property tag array but cannot add new tags.

HrAddColumnsEx first calls the callback function if one is furnished, then adds or moves the specified columns, and finally calls IMAPITable::SetColumns.

The lpAllocateBuffer and lpFreeBuffer input parameters point to the MAPIAllocateBuffer and MAPIFreeBuffer functions, respectively. The exact values of the pointers passed to HrAddColumnsEx depend on whether the caller is a client application or a service provider. A client passes pointers to the MAPI functions with the specified names. A service provider passes the pointers it received in its initialization call or retrieved by calling the IMAPISupport::GetMemAllocRoutines method.

See Also

Table Functions, IMAPITable::QueryColumns


HrAllocAdviseSink

The HrAllocAdviseSink function creates an advise sink object, given a context specified by the calling implementation and a callback function to be triggered by an event notification.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

STDAPI HrAllocAdviseSink(
  LPNOTIFCALLBACK lpfnCallback,
  LPVOID lpvContext,
  LPMAPIADVISESINK FAR * lppAdviseSink
);

Parameters

lpfnCallback
[in] Pointer to a callback function based on the NOTIFCALLBACK prototype that MAPI is to call when a notification event occurs for the newly created advise sink.
lpvContext
[in] Pointer to caller data passed to the callback function when MAPI calls it. The caller data can represent an address of significance to the client or provider. Typically, for C++ code, the lpvContext parameter represents a pointer to the address of an object.
lppAdviseSink
[out] Pointer to a pointer to an advise sink object.

Remarks

To use the HrAllocAdviseSink function, a client application or service provider creates an object to receive notifications, creates a notification callback function based on the NOTIFCALLBACK function prototype that goes with that object, and passes a pointer to the object in the HrAllocAdviseSink function as the lpvContext value. Doing so performs a notification; and as part of the notification process, MAPI calls the callback function with the object pointer as the context.

MAPI implements its notification engine asynchronously. In C++, the notification callback can be an object method. If the object generating the notification is not present, the client or provider requesting notification must keep a separate reference count for that object for the object's advise sink.

HrAllocAdviseSink should be used sparingly; it is safer for clients to create their own advise sinks.

See Also

Notification Functions


HrComposeEID

The HrComposeEID function creates a compound entry identifier for an object, usually a message in a message store.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications

HrComposeEID(
  LPMAPISESSION psession,
  ULONG cbStoreRecordKey,
  LPBYTE pStoreRecordKey,
  ULONG cbMsgEID,
  LPENTRYID pMsgEID,
  ULONG FAR * pcbEID,
  LPENTRYID FAR * ppEID
);

Parameters

psession
[in] Pointer to the session in use by the client application.
cbStoreRecordKey
[in] Size, in bytes, of the record key of the message store holding the message or other object. If zero is passed in the cbStoreRecordKey parameter, the ppEID parameter points to a copy of the object's entry identifier.
pStoreRecordKey
[in] Pointer to the record key of the message store containing the message or other object.
cbMsgEID
[in] Size, in bytes, of the entry identifier of the message or other object.
pMsgEID
[in] Pointer to the entry identifier of the object.
pcbEID
[out] Pointer to the size, in bytes, of the returned identifier.
ppEID
[out] Pointer to a pointer to the returned entry identifier. If the value of the cbStoreRecordKey parameter is greater than zero, the ppEID parameter points to a pointer to the compound entry identifier that is created. If cbStoreRecordKey is zero, ppEID points to a pointer to a copy of the object's entry identifier.

Remarks

If the message or other object for which the compound entry identifier is being created resides in a message store, the identifier is created from the object's entry identifier and the store's record key. If the object is not in a store, that is, if the byte count for the store record key passed in cbStoreRecordKey is zero, the object's entry identifier is simply copied.

The HrComposeEID function, primarily for use with CMC, enables CMC-based applications to work with objects in multiple stores through the use of compound entry identifiers. An application can call the HrDecomposeEID function to split the compound entry identifier into its original constituents.

See Also

Entry Identifier Functions, HrComposeMsgID, HrDecomposeMsgID


HrComposeMsgID

The HrComposeMsgID function creates an ASCII string representing a compound entry identifier for an object, usually a message in a message store.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications

HrComposeMsgID(
  LPMAPISESSION psession,
  ULONG cbStoreRecordKey,
  LPBYTE pStoreRecordKey,
  ULONG cbMsgEID,
  LPENTRYID pMsgEID,
  LPTSTR FAR * pszMsgID
);

Parameters

psession
[in] Pointer to the session in use by the client application.
cbStoreRecordKey
[in] Size, in bytes, of the record key of the message store containing the message or other object. If zero is passed in the cbStoreRecordKey parameter, the pszMsgID parameter points to a copy of the entry identifier converted to text.
pStoreRecordKey
[in] Pointer to the record key of the message store containing the message or other object.
cbMsgEID
[in] Size, in bytes, of the entry identifier of the message or other object.
pMsgEID
[in] Pointer to the entry identifier of the object.
pszMsgID
[out] Pointer to the returned ASCII string. If the cbStoreRecordKey parameter is greater than zero, the pszMsgID parameter points to a compound entry identifier converted to text. If cbStoreRecordKey is zero, pszMsgID points to a noncompound entry identifier converted to text.

Remarks

If the message or other object for which the compound entry identifier is being created resides in a message store, the identifier string is created from the object's entry identifier and the store's record key. If the object is not in a store, that is, if the byte count for the store record key passed in the cbStoreRecordKey parameter is zero, the object's entry identifier is simply copied and converted into a string.

Calling the HrComposeMsgID function is equivalent to calling the HrComposeEID function and then the HrSzFromEntryID function.

HrComposeMsgID enables client applications based on Simple MAPI and OLE to work with objects in multiple stores through the use of compound entry identifiers. An application can call the HrDecomposeMsgID function to split the compound entry identifier into its original constituents.

See Also

Entry Identifier Functions


HrDecomposeEID

The HrDecomposeEID function separates the compound entry identifier of an object, usually a message in a message store, into the entry identifier of that object within the store and the store's entry identifier.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications

HrDecomposeEID(
  LPMAPISESSION psession,
  ULONG cbEID,
  LPENTRYID pEID,
  ULONG FAR * pcbStoreEID,
  LPENTRYID FAR * ppStoreEID ,
  ULONG FAR * pcbMsgEID,
  LPENTRYID FAR * ppMsgEID
);

Parameters

psession
[in] Pointer to the session in use by the client application.
cbEID
[in] Size, in bytes, of the compound entry identifier to be separated.
pEID
[in] Pointer to the compound entry identifier to be separated.
pcbStoreEID
[out] Pointer to the returned size, in bytes, of the entry identifier of the message store containing the object. If the pEID parameter points to a noncompound entry identifier, then the pcbStoreEID parameter points to a value of zero.
ppStoreEID
[out] Pointer to a pointer to the returned entry identifier of the message store containing the object. If the pEID parameter points to a noncompound entry identifier, NULL is returned in the ppStoreEID parameter.
pcbMsgEID
[out] Pointer to the returned size, in bytes, of the entry identifier of the object. If the pEID parameter points to a noncompound entry identifier, then the pcbMsgEID parameter is equal to the value of the cbEID parameter.
ppMsgEID
[out] Pointer to a pointer to the returned entry identifier of the object. If the pEID parameter points to a noncompound entry identifier, ppMsgEID points to a pointer to a copy of the noncompound entry identifier.

Remarks

If the identifier specified by the pEID parameter is compound, it is split into the entry identifier of the object within its message store and the store's entry identifier. Noncompound entry identifier strings are simply copied. The compound identifier to be separated is usually one created by the HrComposeEID function.

Notes to Callers

The memory that holds the pEID parameter is released upon successful completion of this function. The calling implementation is responsible for freeing memory for the output parameters.

See Also

Entry Identifier Functions


HrDecomposeMsgID

The HrDecomposeMsgID function separates the ASCII representation of the compound entry identifier of an object, usually a message in a message store, into the entry identifier of that object within the store and the store's entry identifier.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications

HrDecomposeMsgID(
  LPMAPISESSION psession,
  LPTSTR szMsgID,
  ULONG FAR * pcbStoreEID,
  LPENTRYID FAR * ppStoreEID ,
  ULONG FAR * pcbMsgEID,
  LPENTRYID FAR * ppMsgEID
);

Parameters

psession
[in] Pointer to the session in use by the client application.
szMsgID
[in] The string representing the entry identifier of the object.
pcbStoreEID
[out] Pointer to the returned size, in bytes, of the entry identifier of the message store containing the object. If the szMsgID parameter points to a noncompound entry identifier string, then the pcbStoreEID parameter points to zero.
ppStoreEID
[out] Pointer to a pointer to the returned entry identifier of the message store containing the object. If the szMsgID parameter points to a noncompound entry identifier, NULL is returned in the ppStoreEID parameter.
pcbMsgEID
[out] Pointer to the returned size, in bytes, of the entry identifier of the object within its store. If the szMsgID parameter points to a noncompound entry identifier string, then the pcbMsgEID parameter is equal to the value of the cbEID parameter.
ppMsgEID
[out] Pointer to a pointer to the returned entry identifier string of the object within its store. If the szMsgID parameter points to a noncompound entry identifier, ppMsgEID points to a pointer to a converted copy of the noncompound entry identifier.

Remarks

If the identifier specified by the szMsgID parameter is compound, it is converted from ASCII and split into the entry identifier of the object within its message store and the store's entry identifier. Noncompound entry identifier strings are simply converted and copied. The compound identifier string to be separated is usually one created by the HrComposeMsgID function.

Calling the HrDecomposeMsgID function is equivalent to calling the HrEntryIDFromSz function and then the HrDecomposeEID function.

See Also

Entry Identifier Functions


HrDispatchNotifications

The HrDispatchNotifications function forces dispatching of all queued notifications.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

HRESULT HrDispatchNotifications(
  ULONG ulFlags
);

Parameters

ulFlags

Reserved; must be zero.

Remarks

The HrDispatchNotifications function causes MAPI to dispatch all notifications that are currently queued in the MAPI notification engine without waiting for a message dispatch. This can have a beneficial effect on memory utilization. For more information, see Forcing a Notification.

Notes to Callers

Some applications wait for a notification message in a timeout loop using the Windows PeekMessage and DispatchMessage functions. On all but the fastest platforms, such applications might experience poor performance or even blockage of notifications. Using HrDispatchNotifications not only reduces code but improves performance.

See Also

Notification Functions


HrEntryIDFromSz

The HrEntryIDFromSz function recreates an entry identifier from its ASCII encoding.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications

HRESULT HrEntryIDFromSz(
  LPTSTR sz,
  ULONG FAR * pcb,
  LPENTRYID FAR * ppentry
);

Parameters

sz
[in] Pointer to the ASCII string from which to create an entry identifier.
pcb
[out] Pointer to the size, in bytes, of the entry identifier pointed to by the ppentry parameter.
ppentry
[out] Pointer to a pointer to the returned ENTRYID structure containing the new entry identifier.

Remarks

The HrEntryIDFromSz and HrSzFromEntryID functions provide conversion between the string and binary formats of entry identifiers. Simple MAPI uses ASCII strings for message identifiers, while MAPI uses structures with binary data.

A client application using Simple MAPI for most message operations may need to resort to MAPI in some cases. The only folder recognized by Simple MAPI is the Inbox, and if the client needs to access messages in another folder, it must use MAPI methods to look through that folder's contents table, which holds message entry identifiers.

Notes to Callers

The HrEntryIDFromSz function allocates memory for the ASCII string using the MAPIAllocateBuffer function.

See Also

Entry Identifier Functions


HrGetOneProp

The HrGetOneProp function retrieves the value of a single property from a property interface, that is, an interface derived from IMAPIProp.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

HrGetOneProp(
  LPMAPIPROP pmp,
  ULONG ulPropTag,
  LPSPropValue FAR * ppprop
);

Parameters

pmp
[in] Pointer to the IMAPIProp interface from which the property value is to be retrieved.
ulPropTag
[in] Property tag of the property to be retrieved.
ppprop
[out] Pointer to a pointer to the returned SPropValue structure defining the retrieved property value.

Return Values

MAPI_E_NOT_FOUND
The requested property is not available from the specified interface.

Remarks

Unlike the IMAPIProp::GetProps method, the HrGetOneProp function never returns any warning. Because it retrieves only one property, it simply either succeeds or fails. For retrieving multiple properties, GetProps is faster.

You can set or change a single property with the HrSetOneProp function.

See Also

Properties Functions


HrIStorageFromStream

The HrIStorageFromStream function layers an IStorage interface onto an IStream object.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

HRESULT HrIStorageFromStream(
  LPUNKNOWN lpUnkIn,
  PIID lpInterface,
  ULONG ulFlags,
  LPSTORAGE FAR * lppStorageOut
);

Parameters

lpUnkIn
[in] Pointer to the IUnknown object implementing IStream.
lpInterface
[in] Pointer to the interface identifier (IID) for the stream object. Any of the following values can be passed in the lpInterface parameter: NULL, IID_IStream, or IID_ILockBytes. Passing NULL in lpInterface is the same as passing IID_IStream.
ulFlags
[in] Bitmask of flags that controls how the storage object is to be created relative to the stream. The default setting is STGSTRM_RESET, which gives the storage object read-only access and starts it at position zero of the stream. The following flags can be set in any combination, except as noted:
STGSTRM_CREATE
Creates a new storage object for the stream object. This flag cannot be set if the STGSTRM_RESET flag is set.
STGSTRM_CURRENT
Starts storage at the current position of the stream. This flag cannot be set if the STGSTRM_RESET flag is set.
STGSTRM_MODIFY
Allows the calling service provider to write to the returned storage. This flag cannot be set if the STGSTRM_RESET flag is set.
STGSTRM_RESET
Starts storage at position zero. This flag cannot be set if any other flag is set.
lppStorageOut
[out] Pointer to a pointer to the returned IStorage object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Message store providers support the HrIStorageFromStream function using the IStorage interface for attachments. Store providers must implement the IStream interface. HrIStorageFromStream provides the IStorage interface for the IStream object. It is possible to pass either an ILockBytes or an IStream interface in lpUnkIn.

See Also

IStorage Functions


HrQueryAllRows

The HrQueryAllRows function retrieves all rows of a table.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

HRESULT HrQueryAllRows(
  LPMAPITABLE ptable,
  LPSPropTagArray ptaga,
  LPSRestriction pres,
  LPSSortOrderSet psos,
  LONG crowsMax,
  LPSRowSet FAR * pprows
);

Parameters

ptable
[in] Pointer to the MAPI table from which rows are retrieved.
ptaga
[in] Pointer to an SPropTagArray structure containing an array of property tags indicating table columns. These tags are used to select the specific columns to be retrieved. If the ptaga parameter is NULL, HrQueryAllRows retrieves the entire column set of the current table view passed in the ptable parameter.
pres
[in] Pointer to an SRestriction structure containing retrieval restrictions. If the pres parameter is NULL, HrQueryAllRows makes no restrictions.
psos
[in] Pointer to an SSortOrderSet structure identifying the sort order of the columns to be retrieved. If the psos parameter is NULL, the default sort order for the table is used.
crowsMax
[in] Maximum number of rows to be retrieved. If the value of the crowsMax parameter is zero, no limit on the number of rows retrieved is set.
pprows
[out] Pointer to a pointer to the returned SRowSet structure containing an array of pointers to the retrieved table rows.

Return Values

S_OK
The call retrieved the expected rows of a table.
MAPI_E_TABLE_TOO_BIG
The number of rows in the table is larger than the number passed for the crowsMax parameter.

Remarks

A client application or service provider has no control over the number of rows HrQueryAllRows attempts to retrieve, other than by imposing a restriction pointed to by the pres parameter. The crowsMax parameter does not limit the retrieval to a certain number of table rows, but rather defines a maximum amount of memory available to hold all retrieved rows. The only protection against massive memory overflow is the stopgap feature provided by setting crowsMax. The error return MAPI_E_TABLE_TOO_BIG means the table contains too many rows to be held all at once in memory.

Tables that are typically small, such as a message store table or a provider table, usually can be safely retrieved with HrQueryAllRows. Tables at risk of being very large, such as a contents table or even a recipients table, should be traversed in subsections using the IMAPITable::QueryRows method.

If any table properties are undefined when HrQueryAllRows is called, they are returned with property type PT_NULL and property identifier PROP_ID_NULL

See Also

Table Functions


HrSetOneProp

The HrSetOneProp function sets or changes the value of a single property on a property interface, that is, an interface derived from IMAPIProp.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

HrSetOneProp(
  LPMAPIPROP pmp,
  LPSPropValue pprop
);

Parameters

pmp
[in] Pointer to an IMAPIProp interface on which the property value is to be set or changed.
pprop
[in] Pointer to the SPropValue structure defining the property to be set or changed.

Remarks

Unlike the IMAPIProp::SetProps method, the HrSetOneProp function never returns any warning. Because it sets only one property, it simply either succeeds or fails. For setting or changing multiple properties, SetProps is faster.

You can retrieve a single property with the HrGetOneProp function.

See Also

Properties Functions


HrSzFromEntryID

The HrSzFromEntryID function encodes an entry identifier into an ASCII string.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications

HrSzFromEntryID(
  ULONG cb,
  LPENTRYID pentry,
  LPTSTR FAR * psz
);

Parameters

cb
[in] Size, in bytes, of the entry identifier pointed to by the pentry parameter.
pentry
[in] Pointer to an ENTRYID structure containing the entry identifier to be encoded.
psz
[out] Pointer to the returned ASCII string.

Remarks

The HrEntryIDFromSz and HrSzFromEntryID functions provide conversion between the string and binary formats of entry identifiers. Simple MAPI uses ASCII strings for message identifiers, while MAPI uses structures with binary data.

A client application using Simple MAPI for most message operations may need to resort to MAPI in some cases. The only folder recognized by Simple MAPI is the Inbox, and if the client needs to access messages in another folder, it must use MAPI methods to look through that folder's contents table, which holds message entry identifiers. When the client finds the entry identifier for the desired message, it can call HrSzFromEntryID to convert the entry identifier to a Simple MAPI identifier string so the message can be manipulated in Simple MAPI. Then the client can call the Simple MAPI MAPIReadMail function to retrieve the required information about the message.

Notes to Callers

The HrSzFromEntryID function allocates memory for the ASCII string using the MAPIAllocateBuffer function.

See Also

Entry Identifier Functions


HrThisThreadAdviseSink

The HrThisThreadAdviseSink function creates an advise sink that wraps an existing advise sink for thread safety.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications

HrThisThreadAdviseSink(
  LPMAPIADVISESINK lpAdviseSink,
  LPMAPIADVISESINK FAR * lppAdviseSink
);

Parameters

lpAdviseSink
[in] Pointer to the advise sink to be wrapped.
lppAdviseSink
[out] Pointer to a pointer to a new advise sink that wraps the advise sink pointed to by the lpAdviseSink parameter.

Remarks

The purpose of the wrapper is to ensure that notification is called on the same thread that called the HrThisThreadAdviseSink function. This function is used to protect notification callbacks that must run on a particular thread.

Client applications should use HrThisThreadAdviseSink to restrict when notifications are generated, that is, when calls are made to the IMAPIAdviseSink::OnNotify method of the advise sink object passed by the client in a previous Advise call. If notifications are allowed to be generated arbitrarily, a notification implementation might force a client into multithreaded operation when that would not be appropriate. For example, a client might use a library, such as one of the Microsoft Foundation Class Libraries, that does not support multithreaded calls. Notification on a different thread would make such a client difficult to test and prone to error.

HrThisThreadAdviseSink ensures that OnNotify calls occur only at these appropriate times:

  • During processing of a call to any MAPI method.
  • During processing of Windows messages.

When HrThisThreadAdviseSink is implemented, any calls to the new advise sink's OnNotify method on any thread cause the original notification method to be executed on the thread on which HrThisThreadAdviseSink was called.

For more information on notification and advise sinks, see Event Notification in MAPI and Implementing an Advise Sink Object.

See Also

Notification Functions


HrValidateIPMSubtree

The HrValidateIPMSubtree function adds standard interpersonal message (IPM) folders to a message store.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications

HrValidateIPMSubtree(
  LPMDB lpMDB,
  ULONG ulFlags,
  ULONG FAR * lpcValues,
  LPSPropValue FAR * lppProps,
  LPMAPIERROR FAR * lppMapiError
);

Parameters

lpMDB
[in] Pointer to the message store object to which to add the folders.
ulFlags
[in] Bitmask of flags used to control how the folders are created. The following flags can be set:
MAPI_FORCE_CREATE
The folders should be verified before creation, even if message store properties indicate that they are valid. A client application typically sets this flag when an error indicates that the structure of an existing folder has been damaged.
MAPI_FULL_IPM_TREE
The full set of IPM folders should be created in the message store's root folder. The folder titles in the hierarchy are:

Folder Views
Common Views
Search Root*
IPM Subtree*
Inbox
Outbox
Deleted Items*
Sent Items

where the three folders marked with * are the minimum set created even when the MAPI_FULL_IPM_TREE flag has not been set. A client application typically sets this flag when the message store in which the folders are to be created is the default store.

lpcValues
[in, out] Pointer to the number of SPropValue structures in the array returned in the lppProps parameter. The value of the lpcValues parameter can be zero if lppProps is NULL.
lppProps
[in, out] Pointer to a pointer to an array of SPropValue structures containing property values for the PR_VALID_FOLDER_MASK property and for the appropriate folder entry identifier properties. If HrValidateIPMSubtree creates an Inbox in the message store, the SPropValue array includes an Inbox entry identifier with a special property tag coded as PROP_TAG(PT_BINARY, PROP_ID_NULL). The lppProps parameter can be NULL, indicating that the calling implementation does not require that an SPropValue array be returned.
lppMapiError
[out] Pointer to a pointer to a MAPIERROR structure containing version, component, and context information for an error. The lppMAPIError parameter is set to NULL if no MAPIERROR structure is returned.

Remarks

MAPI uses the HrValidateIPMSubtree function internally to construct the standard IPM subtree in a message store when the store is first opened, or when a store is made the default store. This function can also be used by client applications to validate or repair standard message folders.

HrValidateIPMSubtree always creates the Search Root and IPM Subtree folders in the store's root folder and the Deleted Items folder in the IPM Subtree folder. The IPM Subtree folder is the root of the IPM hierarchy in that message store. The Search Root folder can be used as the root of a subtree for search-results folders.

IPM clients should display their folder view starting at the IPM subtree root folder and showing child folders beneath it. Information in the root folder of a message store should not appear in a client's user interface. This functionality means that if a client must hide information, the information can be put in the IPM subtree root directory, where it is not visible to the user. In contrast, non-IPM applications that require messages and folders to be invisible to the user, for example in a server-based message store, can put them outside the IPM hierarchy.

HrValidateIPMSubtree sets the PR_VALID_FOLDER_MASK property to indicate whether each IPM folder it creates has a valid entry identifier. The following entry identifier properties of the message store are set to the entry identifiers of the corresponding folders and returned in the lppProps parameter along with PR_VALID_FOLDER_MASK:

PR_COMMON_VIEWS_ENTRYID
PR_FINDER_ENTRYID
PR_IPM_OUTBOX_ENTRYID
PR_IPM_SENTMAIL_ENTRYID
PR_IPM_SUBTREE_ENTRYID
PR_IPM_WASTEBASKET_ENTRYID
PR_VIEWS_ENTRYID
A placeholder PROP_TAG for the IPM Inbox (PT_BINARY, PROP_ID_NULL).

See Also

IMAPISession::OpenMsgStore


LAUNCHWIZARDENTRY

The LAUNCHWIZARDENTRY function prototype defines a function that starts the Profile Wizard application for the purpose of adding one or more message services to a profile.

Quick Info

Header file: | MAPIWZ.H
Defined function implemented by: | MAPI
Defined function called by: | Client applications

HRESULT LAUNCHWIZARDENTRY(
  HWND hParentWnd,
  ULONG ulFlags,
  LPCTSTR FAR * lppszServiceNameToAdd,
  ULONG cbBufferMax,
  LPTSTR lpszNewProfileName
);

Parameters

hParentWnd
[in] A handle to the caller's parent window. If the caller does not have a parent window, the hParentWnd parameter should be NULL.
ulFlags
[in] Bitmask of flags indicating options for the Profile Wizard. The following flags can be set:
MAPI_PW_ADD_SERVICE_ONLY
The Profile Wizard is to add only the message services listed through the lppszServiceNameToAdd parameter, and not display its page for selecting message services.
MAPI_PW_FIRST_PROFILE
The profile to be created is the first one for this workstation.
MAPI_PW_HIDE_SERVICES_LIST
The Profile Wizard's page for selecting message services should not be displayed.
MAPI_PW_LAUNCHED_BY_CONFIG
The Profile Wizard was launched by the Control Panel configuration application.
MAPI_PW_PROVIDER_UI_ONLY
Only the service providers's configuration dialog boxes should be displayed and the Profile Wizard's pages should not appear. This flag can only be set if the MAPI_PW_ADD_SERVICE_ONLY flag is set.
lppszServiceNameToAdd
[in] Pointer to an array of strings containing the names of the message services to be added to the profile. The array must terminate with a NULL value.
cbBufferMax
[in] Size of the buffer pointed to by the lpszNewProfileName parameter.
lpszNewProfileName
[out] Pointer to a string buffer where the function based on LAUNCHWIZARDENTRY returns the name of the created profile.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_CALL_FAILED
An error of unexpected or unknown origin prevented the operation from completing. Possibilities include failure to initialize the MAPI subsystem for the Profile Wizard, inability to access the default profile, and an error return from the dialog box.

Remarks

The MAPI implementation of the LAUNCHWIZARDENTRY function prototype is the entry point into the MAPI Profile Wizard application. MAPI names this entry point LaunchWizard.

When the MAPI_PW_ADD_SERVICE_ONLY flag is set in the ulFlags parameter, the following rules apply:

  • The MAPI_PW_LAUNCHED_BY_CONFIG flag inhibits the welcome page from being displayed.
  • The MAPI_PW_HIDE_SERVICES_LIST and MAPI_PW_PROVIDER_UI_ONLY flags are useful only when there is no default profile. In this case these flags determine which Profile Wizard page is to be displayed.
  • If a default profile exists, none of the Profile Wizard pages are to be displayed.
  • If a default profile exists, only one message service is listed through the lppszServiceNameToAdd parameter, and that message service is already in the default profile, the Profile Wizard returns S_OK without adding anything to the profile.

For every message service to be added to the profile, the Profile Wizard calls the service's entry point function based on the MSGSERVICEENTRY prototype. For each service provider selected from a message service to be added to the profile, the Profile Wizard calls the provider's entry point function based on the WIZARDENTRY prototype. During interactive configuration, every user event in the property pages causes the Profile Wizard to call the provider's callback function based on the SERVICEWIZARDDLGPROC prototype.

If a service provider being added to the profile supports the Profile Wizard pages, it must allow programmatic configuration of the profile. For more information on creating profiles, see Creating and Configuring a Profile.

See Also

Profile Wizard Functions


LPFNBUTTON

The LPFNBUTTON function prototype defines a callback function that MAPI calls to activate an optional button control in an address book dialog box. This button is typically a Details button.

Quick Info

Header file: | MAPIDEFS.H
Defined function implemented by: | Service providers
Defined function called by: | MAPI

SCODE (STDMETHODCALLTYPE FAR * LPFNBUTTON) (
  ULONG ulUIParam,
  LPVOID lpvContext,
  ULONG cbEntryID,
  LPENTRYID lpSelection,
  ULONG ulFlags
);

Parameters

ulUIParam
[in] Handle of the parent windows for any dialog boxes or windows this function displays.
lpvContext
[in] Pointer to an arbitrary value passed to the callback function when MAPI calls it. This value can represent an address of significance to the client application. Typically, for C++ code, lpvContext represents a pointer to the address of a C++ object.
cbEntryID
[in] Size, in bytes, of the entry identifier pointed to by the lpSelection parameter.
lpSelection
[in] Pointer to the entry identifier defining the selection within the dialog box.
ulFlags
Reserved; must be zero.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Client applications call a callback function based on the LPFNBUTTON prototype to define a button in a details dialog box. The client passes a pointer to the callback function in calls to the IAddrBook::Details method.

Service providers call a hook function based on the LPFNBUTTON prototype to define a button in a details dialog box. The provider passes a pointer to this hook function in calls to the IMAPISupport::Details method.

In both cases, when the dialog box is displayed and the user chooses the defined button, MAPI calls LPFNBUTTON.

See Also

BuildDisplayTable


LPropCompareProp

The LPropCompareProp function compares two property values to determine if they are equal.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

LONG LPropCompareProp(
  LPSPropValue lpSPropValueA,
  LPSPropValue lpSPropValueB
);

Parameters

lpSPropValueA
[in] Pointer to an SPropValue structure defining the first property value to be compared.
lpSPropValueB
[in] Pointer to an SPropValue structure defining the second property value to be compared.

Remarks

Use the LPropCompareProp function only if the types of the two properties to be compared are the same.

Before calling LPropCompareProp, a client application or service provider must first retrieve the properties for comparison with a call to the IMAPIProp::GetProps method. When a client or provider calls LPropCompareProp, the function first examines the property tags to ensure that the comparison of property values is valid. The function then compares the property values, returning an appropriate value.

If the property values are unequal, LPropCompareProp determines which one is the greater. The properties that LPropCompareProp compares do not have to belong to the same object.

LPropCompareProp returns one of the following values for most property types:

  • Less than zero if the value indicated by the lpSPropValueA parameter is less than that indicated by the lpSPropValueB parameter.
  • Greater than zero if the value indicated by lpSPropValueA is greater than that indicated by lpSPropValueB.
  • Zero if the value indicated by lpSPropValueA equals the value indicated by lpSPropValueB.

For property types that have no intrinsic ordering, such as Boolean or error types, the LPropCompareProp function returns an undefined value if the two property values are not equal. This undefined value is nonzero and consistent across calls.

See Also

Properties Functions


MAPIAdminProfiles

The MAPIAdminProfiles function creates a profile administration object.

Quick Info

Header file: | MAPIX.H
Implemented by: | MAPI
Called by: | Client applications

HRESULT MAPIAdminProfiles(
  ULONG ulFlags,
  LPPROFADMIN FAR * lppProfAdmin
);

Parameters

ulFlags
[in] Bitmask of flags indicating options for the service entry function. The following flag can be set:
MAPI_UNICODE
The passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lppProfAdmin
[out] Pointer to a pointer to the new profile administration object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

See Also

IProfAdmin::CreateProfile


MAPIAllocateBuffer

The MAPIAllocateBuffer function allocates a memory buffer.

Quick Info

Header file: | MAPIX.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE MAPIAllocateBuffer(
  ULONG cbSize,
  LPVOID FAR * lppBuffer
);

Parameters

cbSize
[in] Size, in bytes, of the buffer to be allocated.
lppBuffer
[out] Pointer to the returned allocated buffer.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

During MAPIAllocateBuffer call processing, the calling implementation acquires a block of memory from the operating system. The memory buffer is allocated on an even-numbered byte address. On platforms where long integer access is more efficient, the operating system allocates the buffer on an address whose size in bytes is a multiple of four.

Calling the MAPIFreeBuffer function releases the memory buffer allocated by MAPIAllocateBuffer, by calling the MAPIAllocateMore function and any buffers linked to it, when the memory is no longer needed.

See Also

Memory Management Functions


MAPIAllocateMore

The MAPIAllocateMore function allocates a memory buffer that is linked to another buffer previously allocated with the MAPIAllocateBuffer function.

Quick Info

Header file: | MAPIX.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE MAPIAllocateMore(
  ULONG cbSize,
  LPVOID lpObject,
  LPVOID FAR * lppBuffer
);

Parameters

cbSize
[in] Size, in bytes, of the new buffer to be allocated.
lpObject
[in] Pointer to an existing MAPI buffer allocated using MAPIAllocateBuffer.
lppBuffer
[out] Pointer to the returned, newly allocated buffer.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

During MAPIAllocateMore call processing, the calling implementation acquires a block of memory from the operating system. The memory buffer is allocated on an even-numbered byte address. On platforms where long integer access is more efficient, the operating system allocates the buffer on an address whose size in bytes is a multiple of four.

The only way to release a buffer allocated with MAPIAllocateMore is to pass the buffer pointer specified in the lpObject parameter to the MAPIFreeBuffer function. The link between the memory buffers allocated with MAPIAllocateBuffer and MAPIAllocateMore enables MAPIFreeBuffer to release both buffers with a single call.

See Also

Memory Management Functions


MAPIDeInitIdle

The MAPIDeInitIdle function shuts down the MAPI idle engine for the calling application.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

VOID MAPIDeInitIdle(void)

Parameters

None.

Remarks

A client application or service provider should call MAPIDeInitIdle when it no longer needs the idle engine, for example, when it is about to stop processing.

Every call to MAPIInitIdle must be matched by a subsequent call to MAPIDeInitIdle, or the idle engine is left running for the calling application.

The following functions deal with the MAPI idle engine and with idle routines based on the FNIDLE function prototype:

Idle routine function | Usage
ChangeIdleRoutine | Changes the characteristics of a registered idle routine.
DeregisterIdleRoutine | Removes a registered idle routine from the MAPI system.
EnableIdleRoutine | Disables or re-enables a registered idle routine without removing it from the MAPI system.
FtgRegisterIdleRoutine | Adds an idle routine to the MAPI system, with or without enabling it.
MAPIDeInitIdle | Shuts down the MAPI idle engine for the calling application.
MAPIInitIdle | Initializes the MAPI idle engine for the calling application.

When all foreground tasks for the platform become idle, the MAPI idle engine calls the highest priority idle routine that is ready to execute. There is no guarantee of calling order among idle routines of the same priority.

See Also

Idle Routine Functions


MAPIFreeBuffer

The MAPIFreeBuffer function frees a memory buffer allocated with a call to the MAPIAllocateBuffer function or the MAPIAllocateMore function.

Quick Info

Header file: | MAPIX.H
Implemented by: | MAPI
Called by: | Client applications and service providers

ULONG MAPIFreeBuffer(
  LPVOID lpBuffer
);

Parameters

lpBuffer
[in] Pointer to a previously allocated memory buffer. If NULL is passed in the lpBuffer parameter, MAPIFreeBuffer does nothing.

Return Values

S_OK
The call succeeded and freed the memory requested. MAPIFreeBuffer can also return S_OK on already freed locations or if memory block is not allocated with MAPIAllocateBuffer and MAPIAllocateMore.

Remarks

Usually, when a client application or service provider calls MAPIAllocateBuffer or MAPIAllocateMore, the operating system constructs in one contiguous memory buffer one or more complex structures with multiple levels of pointers. When a MAPI function or method creates a buffer with such contents, a client can later free all the structures contained in the buffer by passing to MAPIFreeBuffer the pointer to the buffer returned by the MAPI function that created the buffer. For a service provider to free a memory buffer using MAPIFreeBuffer, it must pass the pointer to that buffer returned with the provider's support object.

The call to MAPIFreeBuffer to free a particular buffer must be made as soon as a client or provider is finished using this buffer. Simply calling the MAPILogoff function at the end of a MAPI session does not automatically release memory buffers.

A client or service provider should operate on the assumption that the pointer passed in lpBuffer is invalid after a successful return from MAPIFreeBuffer. If the pointer indicates either a memory block not allocated by the messaging system through MAPIAllocateBuffer or MAPIAllocateMore or a free memory block, the behavior of MAPIFreeBuffer is undefined.

Note Passing a null pointer to MAPIFreeBuffer makes application cleanup code simpler and smaller because MAPIFreeBuffer can initialize pointers to NULL and then free them in the cleanup code without having to test them first.

MAPIFreeBuffer is exported, with a slightly different syntax, by both Simple MAPI and MAPI. For Simple MAPI, it is an entry point function.

See Also

Memory Management Functions, IMAPISupport::GetMemAllocRoutines


MAPIGetDefaultMalloc

The MAPIGetDefaultMalloc function retrieves the address of the default MAPI memory allocation function.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

LPMALLOC MAPIGetDefaultMalloc()

Parameters

None.

Remarks

The MAPIGetDefaultMalloc function returns a pointer to the default MAPI memory allocation function.

See Also

Memory Management Functions


MAPIInitialize

The MAPIInitialize function increments the MAPI subsystem reference count and initializes global data for the MAPI DLL.

Quick Info

Header file: | MAPIX.H
Implemented by: | MAPI
Called by: | Client applications

HRESULT MAPIInitialize(
  LPVOID lpMapiInit
);

Parameters

lpMapiInit
[in] Pointer to a MAPIINIT_0 structure. The lpMapiInit parameter can be set to NULL.

Return Values

S_OK
The MAPI subsystem was initialized successfully.

Remarks

The MAPIInitialize function increments the MAPI reference count for the MAPI subsystem, and the MAPIUninitialize function decrements the internal reference count. Thus, the number of calls to one function must equal the number of calls to the other. MAPIInitialize returns S_OK if MAPI has not been previously initialized.

A client or service provider must call MAPIInitialize before making any other MAPI call. Failure to do so causes client or service provider calls to return the MAPI_E_NOT_INITIALIZED value.

When calling MAPIInitialize from a multithreaded application, set the lpMapiInit parameter to a MAPIINIT_0 structure that is declared as follows:

MAPIINIT_0 MAPIINIT= { 0, MAPI_MULTITHREAD_NOTIFICATIONS}

and call:

MAPIInitialize (&MAPIINIT);

When this structure is declared, MAPI creates a separate thread to handle the notification window, which continues until the initialize reference count falls to zero. A Windows NT service must set the ulflags member of the MAPIINIT_0 structure pointed to by lpMapiInit to MAPI_NT_SERVICE.

Note You cannot call MAPIInitialize or MAPIUninitialize from within a Win32 DllEntryPoint function or any other function that creates or terminates threads. For more information, see Using Thread-Safe Objects.

MAPIInitialize does not return any extended error information. Unlike most other MAPI calls, the meanings of its return values are strictly defined to correspond to the particular step of the initialization that failed:

Step 1 Checks parameters and flags.

MAPI_E_INVALID_PARAMETER or MAPI_E_UNKNOWN_FLAGS. Caller passed invalid parameter or flag.

Step 2 Initializes registry keys required by MAPI and confirms the type of operating system. This step only happens if the client process is running as a service under Windows NT and sets the MAPI_NT SERVICE flag in the MAPIINIT_0 structure.

MAPI_E_TOO_COMPLEX. (Windows NT only) The calling process is an NT service and registry keys required by MAPI could not be initialized.

Additional information may be available in the application event log.

Step 3a Checks for compatibility between the current versions of OLE and MAPI.

MAPI_E_VERSION. The version of OLE installed on the workstation is not compatible with this version of MAPI.

Step 3b Initializes OLE.

During this step only, this function can return an error code not listed here. Any error not listed here should be assumed to come from the OLE function CoInitialize.

Step 4 Initializes per-process global variables.

MAPI_E_SESSION_LIMIT. MAPI sets up context specific to the current process. Failures may occur on Win16 if the number of processes exceeds a certain number, or on any system if available memory is exhausted.

Step 5 Initializes shared global variables of all processes.

MAPI_E_NOT_ENOUGH_RESOURCES. Not enough system resources were available to complete the operation.

Step 6 Initializes the notification engine, creates its window and its thread if requested by the MAPI_MULTITHREAD_NOTIFICATIONS flag.

MAPI_E_INVALID_OBJECT. May fail if system resources are exhausted.

Step 7 Loads and initializes the profile provider. Verifies that MAPIInitialize can access the registry key where profile data are stored.

MAPI_E_NOT_INITIALIZED. The profile provider has encountered an error. In a service running under Windows NT version 3.51, the profile provider must first initialize the registry subtree called HKEY_CURRENT_USER, this occurs in Step 2. This process is subject to additional failures, including lack of access rights to the registry.

See Also

MAPI Initialization Functions


MAPIInitIdle

The MAPIInitIdle function initializes the MAPI idle engine for the calling application.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

LONG MAPIInitIdle(
  LPVOID lpvReserved
);

Parameter

lpvReserved
Reserved; must be zero.

Remarks

A client application or service provider must call MAPIInitIdle before calling any other idle engine function.

The MAPIInitIdle function returns zero if initialization is successful, and –1 otherwise. If MAPIInitIdle is called multiple times, all additional calls succeed but are ignored except to increment the reference count.

Every call to MAPIInitIdle must be matched by a subsequent call to MAPIDeInitIdle, or the idle engine is left running for the calling application.

The following functions deal with the MAPI idle engine and with idle routines based on the FNIDLE function prototype:

Idle routine function | Usage
ChangeIdleRoutine | Changes the characteristics of a registered idle routine.
DeregisterIdleRoutine | Removes a registered idle routine from the MAPI system.
EnableIdleRoutine | Disables or re-enables a registered idle routine without removing it from the MAPI system.
FtgRegisterIdleRoutine | Adds an idle routine to the MAPI system, with or without enabling it.
MAPIDeInitIdle | Shuts down the MAPI idle engine for the calling application.
MAPIInitIdle | Initializes the MAPI idle engine for the calling application.

When all foreground tasks for the platform become idle, the MAPI idle engine calls the highest priority idle routine that is ready to execute. There is no guarantee of calling order among idle routines of the same priority.

See Also

Idle Routine Functions


MAPILogonEx

The MAPILogonEx function logs a client application on to a session with the messaging system.

Quick Info

Header file: | MAPIX.H
Implemented by: | MAPI
Called by: | Client applications

HRESULT MAPILogonEx(
  ULONG ulUIParam,
  LPTSTR lpszProfileName,
  LPTSTR lpszPassword,
  FLAGS flFlags,
  LPMAPISESSION FAR * lppSession
);

Parameters

ulUIParam
[in] Handle to the window to which the logon dialog box is modal. If no dialog box is displayed during the call, the ulUIParam parameter is ignored. This parameter can be zero.
lpszProfileName
[in] Pointer to a string containing the name of the profile to use when logging on. This string is limited to 64 characters.
lpszPassword
[in] Pointer to a string containing the password of the profile. The lpszPassword parameter can be NULL whether or not the lpszProfileName parameter is NULL. This string is limited to 64 characters.
flFlags
[in] Bitmask of flags used to control how logon is performed. The following flags can be set:
MAPI_ALLOW_OTHERS
The shared session should be returned, allowing subsequent clients to acquire the session without providing any user credentials.
MAPI_EXPLICIT_PROFILE
The default profile should not be used, and the user should be required to supply a profile.
MAPI_EXTENDED
Log on with extended capabilities. This flag should always be set. The older MAPILogon function is no longer available.
MAPI_FORCE_DOWNLOAD
An attempt should be made to download all of the user's messages before returning. If the MAPI_FORCE_DOWNLOAD flag is not set, messages can be downloaded in the background after the call to MAPILogonEx returns.
MAPI_LOGON_UI
A dialog box should be displayed to prompt the user for logon information if required. When the MAPI_LOGON_UI flag is not set, the calling client does not display a logon dialog box and returns an error value if the user is not logged on. MAPI_LOGON_UI and MAPI_PASSWORD_UI are mutually exclusive.
MAPI_NEW_SESSION
An attempt should be made to create a new MAPI session rather than acquire the shared session. If the MAPI_NEW_SESSION flag is not set, MAPILogonEx uses an existing shared session even if the lpszprofileName parameter is not NULL.
MAPI_NO_MAIL
MAPI should not inform the MAPI spooler of the session's existence. The result is that no messages can be sent or received within the session except through a tightly coupled store and transport pair. A calling client sets this flag if it is acting as an agent, if configuration work must be done, or if the client is browsing the available message stores.
MAPI_NT_SERVICE
The caller is running as a Windows NT service. Callers that are not running as a Windows NT service should not set this flag; callers that are running as a service must set this flag.
MAPI_PASSWORD_UI
A dialog box should be displayed to prompt the user for the profile password. MAPI_PASSWORD_UI cannot be set if MAPI_LOGON_UI is set because the calling client can only present one of the two dialog boxes. This dialog box does not allow the profile name to be changed; the lpszProfileName parameter must be non-NULL.
MAPI_SERVICE_UI_ALWAYS
MAPILogonEx should display a configuration dialog box for each message service in the profile. The dialog boxes are displayed after the profile has been chosen but before any message service is logged on. The MAPI common dialog box for logon also contains a check box that requests the same operation.
MAPI_TIMEOUT_SHORT
The logon should fail if blocked for more than a few seconds.
MAPI_UNICODE
The passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
MAPI_USE_DEFAULT
The messaging subsystem should substitute the profile name of the default profile for the lpszProfileName parameter. The MAPI_EXPLICIT_PROFILE flag is ignored unless lpszProfileName is NULL or empty.
lppSession
[out] Pointer to a pointer to the MAPI session interface.

Return Values

S_OK
The logon succeeded.
MAPI_E_LOGON_FAILED
The logon did not succeed, either because one or more of the parameters to MAPILogonEx were invalid or because there were too many sessions open already.
MAPI_E_TIMEOUT
MAPI serializes all logons through a mutex. This is returned if the MAPI_TIMEOUT_SHORT flag was set and another thread held the mutex.
MAPI_E_USER_CANCEL
The user canceled the operation, typically by clicking the Cancel button in a dialog box.

Remarks

MAPI client applications call the MAPILogonEx function to log on to a session with the messaging system. All strings passed in and returned to and from MAPI calls are null-terminated and must be specified in the current character set or code page of the calling client or provider's operating system.

The lpszProfileName parameter is ignored if there is an existing previous session that called MapiLogonEx with the MAPI_ALLOW_OTHERS flag set and if the flag MAPI_NEW_SESSION is not set. If the lpszProfileName parameter is NULL or points to an empty string, and the flFlags parameter includes the MAPI_LOGON_UI flag, the MAPILogonEx function generates a logon dialog box with an empty field for the profile name.

When logging on to a specific profile, a client should pass the MAPI_NEW_SESSION flag into MAPILogonEx in addition to the profile name. Otherwise, if another client has established a shared session by logging on with MAPI_ALLOW_OTHERS, the client will be logged on to the shared session instead of to the profile requested.

The MAPI_EXPLICIT_PROFILE flag does not cause the default profile name to be used when lpszProfileName is NULL or empty unless the MAPI_USE_DEFAULT flag is also present.

The MAPI_NO_MAIL flag has several effects that result in the following when not using the MAPI spooler:

  • No messages can be sent or delivered by the MAPI spooler during this session. Only tightly coupled store and transport providers can send and deliver messages.
  • Server based stores might still send or deliver messages.
  • Messages sent or delivered by server based stores are not processed by any hook providers.
  • Per-message and per-recipient options for transports are not available.
  • The status table does not contain entries for transport providers, and any transport functionality dependent on status objects (such as configuration) is not available.
  • The message spooler row in the status table contains the STATUS_FAILURE value.
  • Piggybacked logons are allowed, but those logons do not cause the previous logon to receive status object updates.

An agent should always log on using the MAPI_NO_MAIL flag.

See Also

MAPI Initialization Functions, IMAPISession::GetMsgStoresTable, IMAPISession::OpenMsgStore


MAPIOpenFormMgr

The MAPIOpenFormMgr function opens an IMAPIFormMgr interface on a form library provider object in the context of an existing session.

Quick Info

Header file: | MAPIFORM.H
Implemented by: | MAPI
Called by: | Client applications

MAPIOpenFormMgr(
  LPMAPISESSION pSession,
  LPMAPIFORMMGR FAR * ppmgr
);

Parameters

pSession
[in] Pointer to the session in use by the client application.
ppmgr
[out] Pointer to the returned IMAPIFormMgr interface.

Remarks

After a client application makes a call to the MAPIOpenFormMgr function, most subsequent forms-related interactions take place through the form library provider or an interface returned by the form library provider. Among other things, the IMAPIFormMgr interface allows the client to work with message handlers and perform resolutions between message classes and form libraries.

See Also

Form Functions


MAPIOpenLocalFormContainer

The MAPIOpenLocalFormContainer function returns an interface pointer to the local form library.

Quick Info

Header file: | MAPIFORM.H
Implemented by: | MAPI
Called by: | Client applications

MAPIOpenLocalFormContainer(
  LPMAPIFORMCONTAINER FAR * ppfcnt
);

Parameters

ppfcnt
[out] Pointer to a pointer to the local form library interface.

Remarks

The interface to which a pointer is returned can be used by third-party installation programs to install application-specific forms into the library without the program first having to log on to MAPI.

See Also

Form Functions


MAPIUninitialize

The MAPIUninitialize function decrements the reference count, cleans up, and deletes per-instance global data for the MAPI DLL.

Quick Info

Header file: | MAPIX.H
Implemented by: | MAPI
Called by: | Client applications

void MAPIUninitialize()

Parameters

None

Remarks

A client application calls the MAPIUninitialize function to end its interaction with MAPI, begun with a call to the MAPIInitialize function. After MAPIUninitialize is called, no other MAPI calls can be made by the client.

MAPIUninitialize decrements the reference count, and the corresponding MAPIInitialize function increments the reference count. Thus, the number of calls to one function must equal the number of calls to the other.

Note You cannot call MAPIInitialize or MAPIUninitialize from within a Win32 DllEntryPoint function or any other function that creates or terminates threads. For more information, see Using Thread-Safe Objects.

See Also

MAPI Initialization Functions


MapStorageSCode

The MapStorageSCode function maps an HRESULT return value from an OLE storage object to a MAPI return value of the SCODE type.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | IMESSAGE.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE MapStorageSCode(
  SCODE StgSCode
);

Parameters

StgSCode
[in] HRESULT return value from an OLE storage object to be mapped to a MAPI SCODE value.

Return Values

S_OK
The call succeeded and returned the expected value.
MAPI_E_CALL_FAILED
The function cannot find a matching value.

Remarks

MAPI provides the MapStorageSCode function for the internal use of MAPI components that base their message implementations on the message DLL. Because these components open OLE storage themselves, they must be able to map error values returned for problems with OLE storage to MAPI SCODE values.

For more information, see Structured Storage.

See Also

IStorage Functions


MSGCALLRELEASE

The MSGCALLRELEASE function prototype defines a callback function that can free an IStorage interface after the final release of an IMessage object built on top of it with the OpenIMsgOnIStg function.

Quick Info

Header file: | IMESSAGE.H
Defined function implemented by: | Client applications and service providers
Defined function called by: | MAPI

void(
  ULONG ulCallerData,
  LPMESSAGE lpMessage
);

Parameters

ulCallerData
[in] Contains calling application information about the IMessage interface.
lpMessage
[in] Pointer to the top-level message and attachments that have been released.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

See Also

IMessage-On-IStorage Functions


MSGSERVICEENTRY

The MSGSERVICEENTRY function prototype defines a message service entry point function to support message service configuration.

Quick Info

Header file: | MAPISPI.H
Defined function implemented by: | Message services
Defined function called by: | MAPI

HRESULT MSGSERVICEENTRY(
  HINSTANCE hInstance,
  LPMALLOC lpMalloc,
  LPMAPISUP lpMAPISup,
  ULONG ulUIParam,
  ULONG ulFlags,
  ULONG ulContext,
  ULONG cValues,
  LPSPropValue lpProps,
  LPPROVIDERADMIN lpProviderAdmin,
  LPMAPIERROR FAR * lppMapiError
);

Parameters

hInstance
[in] Handle of the instance of the service provider DLL. The handle is typically used to retrieve resources.
lpMalloc
[in] Pointer to a memory allocator object exposing the OLE IMalloc interface. The message service may need to use this allocation method when working with certain interfaces such as IStream.
lpMAPISup
[in] Pointer to an IMAPISupport : IUnknown interface implementation.
ulUIParam
[in] An implementation-specific 32-bit value used for passing user interface information to a function or zero. In applications that run on Microsoft Windows, the ulUIParam parameter is the parent window handle for the configuration dialog box and is of type HWND (cast to a ULONG). A value of zero indicates that there is no parent window.
ulFlags
[in] Bitmask of flags indicating options for the service entry function. The following flags can be set:
MAPI_UNICODE
The passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
MSG_SERVICE_UI_READ_ONLY
The service's configuration user interface should display the current configuration but not allow the user to change it.
SERVICE_UI_ALLOWED
Permits a configuration dialog box to be displayed if necessary. When the SERVICE_UI_ALLOWED flag is set, the dialog box should be displayed only if the lpProps property value array is empty or does not contain a valid configuration. If SERVICE_UI_ALLOWED is not set, a dialog box might still be displayed if the UI_SERVICE_ALWAYS flag is set.
UI_CURRENT_PROVIDER_FIRST
Requests that the configuration dialog box for the active provider be displayed on top of other dialog boxes.
UI_SERVICE_ALWAYS
Requires the message service to display a configuration dialog box. If the UI_SERVICE_ALWAYS flag is not set, a configuration dialog box might still be displayed if the SERVICE_UI_ALLOWED flag is set and valid configuration information is not available from the lpProps property value array. Either SERVICE_UI_ALLOWED or UI_SERVICE_ALWAYS must be set to allow a user interface to be displayed.
ulContext
[in] The configuration operation that MAPI is currently performing. The ulContext parameter will contain one of the following values:
MSG_SERVICE_CONFIGURE
Changes to the service's configuration should be made in the profile. If the UI_SERVICE_ALWAYS flag is set, the service should display its configuration dialog box. The dialog box should also be displayed if the SERVICE_UI_ALLOWED flag is set and the lpProps parameter is empty or does not contain valid configuration data. If lpProps contains valid data, no dialog box should be displayed and the service should use this data for making the configuration change.
MSG_SERVICE_CREATE
The service is being added to a profile. If either the UI_SERVICE_ALWAYS or SERVICE_UI_ALLOWED flag is set, the service should display its configuration dialog box. If neither flag is set, the service should fail.
MSG_SERVICE_DELETE
The service is being removed from a profile. After receiving this event, the service should return S_OK.
MSG_SERVICE_INSTALL
The service has been installed to the user's workstation from a network, floppy disk, or other external medium. After receiving this event, the service usually returns S_OK.
MSG_SERVICE_PROVIDER_CREATE
Requests that the service create an additional instance of a provider. If the service supports this operation, it should call IProviderAdmin::CreateProvider. If the service does not support this operation, it can return MAPI_E_NO_SUPPORT.
MSG_SERVICE_PROVIDER_DELETE
Requests that the service delete a provider instance. If the service supports this operation, it should call IProviderAdmin::DeleteProvider. If the service does not support this operation, it can return MAPI_E_NO_SUPPORT.
MSG_SERVICE_UNINSTALL
The service is being removed. After receiving this event, the service can perform any cleanup tasks that should be done before the service ends and then return with a success value. If the user cancels the removal, the service should return MAPI_E_USER_CANCEL.
cValues
[in] Count of property values in the array pointed to by the lpProps parameter. The value of the cValues parameter is zero if MAPI is passing no property values.
lpProps
[in] Pointer to an optional array of SPropValue structures indicating values for provider-supported properties that the function will use in configuring the message service. The function only uses this parameter if the ulContext parameter is set to MSG_SERVICE_CONFIGURE. This parameter is commonly used to pass the path to a file for a file-based service, such as a personal address book service. If the MSG_SERVICE_CONFIGURE flag is not passed in the ulFlags parameter, the lpProps parameter must be zero.
lpProviderAdmin
[in] Pointer to an IProviderAdmin:IUnknown interface that the function can use to locate profile sections for a specific provider in the current message service.
lppMapiError
[out] Pointer to a MAPIERROR structure. The structure is allocated with the MAPIAllocateBuffer function. All members are optional, although most structures will contain a valid error message string in the lpszError member. If the lpszComponent or lpszError members of the structure are present, their memory must eventually be freed by a single call to MAPIFreeBuffer on the base structure.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_UNCONFIGURED
The service provider has not been configured.
MAPI_E_USER_CANCEL
The user canceled the operation, typically by clicking the Cancel button in a dialog box.
MAPI_E_NO_SUPPORT
The provider either does not support changes to its objects or does not support notification of changes.
MAPI_E_BAD_CHARWIDTH
Either the MAPI_UNICODE flag was set and the implementation does not support Unicode, or MAPI_UNICODE was not set and the implementation only supports Unicode.

Remarks

A function defined using the MSGSERVICEENTRY function prototype enables message services to configure themselves or to perform other service-specific actions. The function primarily furnishes a dialog box in which the user can change settings specific to the message service. It can also support programmatic configuration by using the property value array passed in the lpProps parameter. Programmatic configuration is optional unless the service supports the Profile Wizard, for which it is required.

MAPI calls this entry point from the Control Panel application or in response to a client application calling IMsgServiceAdmin::CreateMsgService or IMsgServiceAdmin::ConfigureMsgService.

MAPI places no restriction on the function name that a message service uses for the MSGSERVICEENTRY prototype but prefers the name ServiceEntry. There is no restriction on the ordinal for the function, and a single provider DLL can contain more than one function. However, only one of the functions can be named ServiceEntry.

MAPI enables a message service to use Windows 95-style property sheets for its configuration dialog boxes. The message service can use the BuildDisplayTable function and the IMAPISupport::DoConfigPropsheet method to simplify configuration dialog box implementation.

It is possible for a user to cancel a MSG_SERVICE_UNINSTALL operation. In this case, the ServiceEntry function should check with the user to verify that the service should not be removed and return MAPI_E_USER_CANCEL if the service remains installed.

A function based on the MSGSERVICEENTRY prototype returns one of the HRESULT values listed. MAPI forwards this value when responding to a client's call to IMsgServiceAdmin::ConfigureMsgService.

Message services that export a service entry function must include the PR_SERVICE_DLL_NAME and PR_SERVICE_ENTRY_NAME properties in the message service section of MAPISVC.INF.


MSProviderInit

The MSProviderInit function initializes a message store provider for operation.

Quick Info

Header file: | MAPISPI.H
Implemented by: | Message store providers
Called by: | MAPI

HRESULT MSProviderInit(
  HINSTANCE hInstance,
  LPMALLOC lpMalloc,
  LPALLOCATEBUFFER lpAllocateBuffer,
  LPALLOCATEMORE lpAllocateMore,
  LPFREEBUFFER lpFreeBuffer,
  ULONG ulFlags,
  ULONG ulMAPIVer,
  ULONG FAR * lpulProviderVer,
  LPMSPROVIDER FAR * lppMSProvider
);

Parameters

hInstance
[in] The instance of the message store provider's dynamic-link library (DLL) that MAPI used when it linked.
lpMalloc
[in] Pointer to a memory allocator object exposing the OLE IMalloc interface. The message store provider may need to use this allocation method when working with certain interfaces such as IStream.
lpAllocateBuffer
[in] Pointer to the MAPIAllocateBuffer function, to be used where required by MAPI to allocate memory.
lpAllocateMore
[in] Pointer to the MAPIAllocateMore function, to be used where required by MAPI to allocate additional memory.
lpFreeBuffer
[in] Pointer to the MAPIFreeBuffer function, to be used where required by MAPI to free memory.
ulFlags
[in] Bitmask of flags. The following flag can be set:
MAPI_NT_SERVICE
The provider is being loaded in the context of a Windows NT service, a special type of process without access to any user interface.
ulMAPIVer
[in] Version number of the service provider interface (SPI) that MAPI.DLL uses. For the current version number, see the MAPISPI.H header file.
lpulProviderVer
[out] Pointer to the version number of the SPI that this message store provider uses.
lppMSProvider
[out] Pointer to a pointer to the initialized message store provider object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_VERSION
The SPI version being used by MAPI is not compatible with the SPI being used by this provider.

Remarks

MAPI calls the entry point function MSProviderInit to initialize a message store provider following a client logon.

Notes to Implementers

A message store provider must implement MSProviderInit as an entry point function in the provider's DLL. The implementation must be based on the MSPROVIDERINIT function prototype, also specified in MAPISPI.H. MAPI defines MSPROVIDERINIT to use the standard MAPI initialization call type, STDMAPIINITCALLTYPE, which causes MSProviderInit to follow the CDECL calling convention. An advantage of CDECL is that calls can be attempted even if the number of calling parameters does not match the number of defined parameters.

A provider can be initialized multiple times, as a result of appearing in several profiles in simultaneous use or of appearing more than once in the same profile. Because the provider object contains context, MSProviderInit must return a different provider object in lppMSProvider for each initialization, even for multiple initializations in the same process.

The provider DLL should not be linked with MAPIX.DLL. Instead, it should use these pointers for memory allocation or deallocation.

The message store provider should use the functions pointed to by lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer for most memory allocation and deallocation. In particular, the provider must use these functions to allocate memory for use by client applications when calling object interfaces such as IMAPIProp::GetProps and IMAPITable::QueryRows. If the provider also expects to use the OLE memory allocator, it should call the IUnknown::AddRef method of the allocator object pointed to by the lpMalloc parameter.

For more information on writing MSProviderInit, see Loading Message Store Providers. For more information on entry point functions, see Implementing a Service Provider Entry Point Function.

See Also

Provider Initialization Functions, ABProviderInit, HPProviderInit, IMSProvider : IUnknown, XPProviderInit


NOTIFCALLBACK

The NOTIFCALLBACK function prototype defines a callback function that MAPI calls to send an event notification. This callback function can only be used when wrapped in an advise sink object created by calling the HrAllocAdviseSink function.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIDEFS.H
Defined function implemented by: | Client applications and service providers
Defined function called by: | MAPI

ULONG (STDAPICALLTYPE NOTIFCALLBACK) (
  LPVOID lpvContext,
  ULONG cNotification,
  LPNOTIFICATION lpNotifications
);

Parameters

lpvContext
[in] Pointer to an arbitrary value passed to the callback function when MAPI calls it. This value can represent an address of significance to the client application or service provider. Typically, for C++ code, the lpvContext parameter represents a pointer to the address of a C++ object.
cNotification
[in] Count of event notifications in the array indicated by the lpNotifications parameter.
lpNotifications
[out] Pointer to the location where this function writes an array of NOTIFICATION structures containing the event notifications.

Remarks

The set of valid return values for the NOTIFCALLBACK function prototype depends on whether the function is implemented by a client application or a service provider. Clients should always return S_OK. Providers can return either S_OK or CALLBACK_DISCONTINUE. CALLBACK_DISCONTINUE is a valid return value for synchronous callback functions only; it requests that MAPI immediately stop processing the callbacks for this notification. When CALLBACK_DISCONTINUE is returned, MAPI sets the lpUlFlags parameter to NOTIFY_CANCELED when it returns from IMAPISupport::Notify.

There are limitations on what a synchronous callback function can do:

  • It cannot cause another synchronous notification to be generated.
  • It cannot display a user interface.

See Also

Notification Functions, IMAPIAdviseSink::OnNotify


OpenIMsgOnIStg

The OpenIMsgOnIStg function builds a new IMessage object on top of an existing OLE IStorage object, to be used within a message session.

Quick Info

Header file: | IMESSAGE.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE OpenIMsgOnIStg(
  LPMSGSESS lpMsgSess,
  LPALLOCATEBUFFER lpAllocateBuffer,
  LPALLOCATEMORE lpAllocateMore,
  LPFREEBUFFER lpFreeBuffer,
  LPMALLOC lpmalloc,
  LPVOID lpMapiSup,
  LPSTORAGE lpStg,
  MSGCALLRELEASE FAR * lpfMsgCallRelease,
  ULONG ulCallerData,
  ULONG ulFlags,
  LPMESSAGE FAR * lppMsg
);

Parameters

lpMsgSess
[in] Pointer to a message session object within which the new IMessage-on-IStorage object is to be created.
lpAllocateBuffer
[in] Pointer to the MAPIAllocateBuffer function, to be used where required by MAPI to allocate memory.
lpAllocateMore
[in] Pointer to the MAPIAllocateMore function, to be used where required by MAPI to allocate additional memory.
lpFreeBuffer
[in] Pointer to the MAPIFreeBuffer function, to be used where required by MAPI to free memory.
lpMalloc
[in] Pointer to a memory allocator object exposing the OLE IMalloc interface. The IMessage interface needs to use this allocation method when working with interfaces such as IStorage and IStream.
lpMapiSup
[in] Optional pointer to a MAPI support object that a service provider can use to call the methods of the IMAPISupport : IUnknown interface.
lpStg
[in, out] Pointer to an OLE IStorage object that is open and has read-only or read/write access. Because IMessage does not support write-only access, OpenIMsgOnIStg does not accept a storage object opened in write-only mode.
lpfMsgCallRelease
[in] Optional pointer to a callback function based on the MSGCALLRELEASE prototype that MAPI is to call following the last release on the IMessage-on-IStorage object.
ulCallerData
[in] 32-bit caller data saved by MAPI with the IMessage-on-IStorage object and passed to the MSGCALLRELEASE based callback function. The data provides context about the IMessage object being released and the IStorage object it was built on top of.
ulFlags
[in] Bitmask of flags used to control whether the OLE IStorage::Commit method is called when the client application or service provider calls the IMessage::SaveChanges method. The following flag can be set:
IMSG_NO_ISTG_COMMIT
The OLE method IStorage::Commit is not to be called when the client or provider calls SaveChanges.
lppMsg
[out] Pointer to a pointer to the opened IMessage object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

Property attributes can only be accessed on property objects, that is, objects implementing the IMAPIProp : IUnknown interface. To make MAPI properties available on an OLE structured storage object, OpenIMsgOnIStg builds an IMessage : IMAPIProp object on top of the OLE IStorage object. The property attributes on such objects can be set or altered with SetAttribIMsgOnIStg and retrieved with GetAttribIMsgOnIStg.

Notes to Callers

A message session should be opened with OpenIMsgSession before OpenIMsgOnIStg is called. Supplying a valid lpMsgSess parameter ensures that the new message is created within a message session so that it is closed when the session is closed. If lpMsgSess is NULL, the message is created independently of any message session. If the client application or service provider that created the message does not release it, as well as all its attachments and open tables, memory is leaked and may cause the application to terminate.

MAPI uses the functions pointed to by lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer for most memory allocation and deallocation, in particular to allocate memory for use by client applications when calling object interfaces such as IMAPIProp::GetProps and IMAPITable::QueryRows. The lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer pointers are optional when the OpenIMsgOnIStg function is called with a valid lpMapiSup parameter.

Because it is dealing with an underlying OLE object, MAPI also needs to use OLE memory allocation. For more information on OLE structured storage objects and OLE memory allocation, see the OLE Programmer's Reference.

If a valid value is supplied for lpMapiSup, IMessage supports the MAPI_DIALOG and ATTACH_DIALOG flags by calling the IMAPISupport::DoProgressDialog method to supply a progress user interface for the IMAPIProp::CopyTo and IMessage::DeleteAttach methods. Also, the IMessage::ModifyRecipients method attempts to convert short-term entry identifiers to long-term entry identifiers by calling the IMAPISupport::OpenAddressBook method and making calls on the resulting address book object. If NULL is passed for lpMapiSup, IMessage ignores MAPI_DIALOG and ATTACH_DIALOG and stores short-term entry identifiers without conversion.

The IStorage object pointed to by the lpStg parameter must be opened in either the STGM_READ or STGM_READWRITE mode. If the STGM_READWRITE mode is used, the STGM_TRANSACTED mode must also be set.

The callback function pointed to by the lpfMsgCallRelease parameter is optional; if provided, it should be based on the MSGCALLRELEASE function prototype. The IMessage interface calls it when the reference count of the IMessage-on-IStorage object is set to zero by the last call to its Release method. The callback function is commonly used to free the underlying IStorage interface. IMessage will not attempt to access the IStorage object pointed to by the lpStg parameter after making the callback.

Some clients or providers might write additional data to the IStorage object beyond what IMessage itself writes when its SaveChanges method is called. The client or provider can use the IMSG_NO_ISTG_COMMIT flag to prevent IMessage from calling the OLE IStorage::Commit method while processing a SaveChanges call; in this case the client or provider must itself commit the IStorage object when the additional data is written. To aid in this, the IMessage implementation guarantees to name all substorages it creates in the IStorage object starting with the string "__", that is, with two underscores. The client or provider can avoid name collisions by keeping its substorage names out of this namespace.

MAPI does not define the behavior of multiple open operations performed on a subobject of a message, such as an attachment, a stream, or an embedded message. MAPI currently allows a subobject that is already open to be opened once more, but MAPI performs the open operation by incrementing the reference count for the existing open object and returning it to the client or provider that called the IMessage::OpenAttach or IMAPIProp::OpenProperty method. This means the access requested for the first open operation on a subobject is the access provided for all subsequent open operations, regardless of the access requested by the operations.

The correct procedure for placing a message into an attachment is to call the IMAPIProp::OpenProperty method with an interface identifier of IID_IMessage. OpenProperty currently also supports creation of message attachments accessible directly on the OLE IStorage interface, that is, using the IID_IStorage interface identifier. IStorage access is supported to allow an easy way to put a Microsoft Word for Windows document into an attachment without converting it to or from the OLE IStream interface. However, IMessage may not behave predictably if OpenIMsgOnIStg is passed an IStorage pointer to the attachment data and then the objects are released in the wrong order.

See Also

IMessage-On-IStorage Functions


OpenIMsgSession

The OpenIMsgSession function creates and opens a message session that groups the messages created within it.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | IMESSAGE.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE OpenIMsgSession(
  LPMALLOC lpMalloc,
  ULONG ulFlags,
  LPMSGSESS FAR * lppMsgSess
);

Parameters

lpMalloc
[in] Pointer to a memory allocator object exposing the OLE IMalloc interface. MAPI needs to use this allocation method when working with the OLE IStorage interface.
ulFlags
Reserved; must be zero.
lppMsgSess
[out] Pointer to a pointer to the returned message session object.

Remarks

A message session is used by client applications and service providers that want to deal with several related MAPI IMessage objects built on top of underlying OLE IStorage objects. The client or provider uses the OpenIMsgSession and CloseIMsgSession functions to wrap the creation of such messages inside a message session. Once the message session is opened, the client or provider passes a pointer to it in a call to OpenIMsgOnIStg to create a new IMessage-on-IStorage object.

A message session keeps track of all IMessage-on-IStorage objects created during the duration of the session, in addition to all the attachments and other properties of the messages. When a client or provider calls CloseIMsgSession, it closes all these objects. Calling CloseIMsgSession is the only way to close IMessage-on-IStorage objects.

OpenIMsgSession is used by clients and providers that require the ability to handle several related messages as OLE IStorage objects. If only one such message is to be open at a time, there is no need to track multiple messages and no reason to create a message session with OpenIMsgSession.

Because it is dealing with an underlying OLE object, MAPI needs to use OLE memory allocation. For more information on OLE structured storage objects and OLE memory allocation, see the OLE Programmer's Reference.

See Also

IMessage-On-IStorage Functions


OpenStreamOnFile

The OpenStreamOnFile function allocates and initializes an OLE IStream object to access the contents of a file.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

HRESULT STDMETHODCALLTYPE OpenStreamOnFile(
  LPALLOCATEBUFFER lpAllocateBuffer,
  LPFREEBUFFER lpFreeBuffer,
  ULONG ulFlags,
  LPTSTR lpszFileName,
  LPTSTR lpszPrefix,
  LPSTREAM FAR * lppStream
);

Parameters

lpAllocateBuffer
[in] Pointer to the MAPIAllocateBuffer function, to be used where required by MAPI to allocate memory.
lpFreeBuffer
[in] Pointer to the MAPIFreeBuffer function, to be used where required by MAPI to free memory.
ulFlags
[in] Bitmask of flags used to control the creation or opening of the file to be accessed through the OLE IStream object. The following flags can be set:
SOF_UNIQUEFILENAME
A temporary file is to be created for the IStream object. If this flag is set, the STGM_CREATE and STGM_READWRITE flags should also be set.
STGM_CREATE
The file is to be created even if one already exists. If the lpszFileName parameter is not set, both this flag and STGM_DELETEONRELEASE must be set. If STGM_CREATE is set, the STGM_READWRITE flag must also be set.
STGM_DELETEONRELEASE
The file is to be deleted when the IStream object is released. If the lpszFileName parameter is not set, both this flag and STGM_CREATE must be set.
STGM_READ
The file is to be created or opened with read-only access.
STGM_READWRITE
The file is to be created or opened with read/write access. If this flag is not set, the STGM_CREATE flag must not be set either.
lpszFileName
[in] The filename, including path and extension, of the file for which OpenStreamOnFile initializes the IStream object. If the SOF_UNIQUEFILENAME flag is set, lpszFileName contains the path to the directory in which to create a temporary file. If lpszFileName is NULL, OpenStreamOnFile obtains an appropriate path from the system, and both the STGM_CREATE and STGM_DELETEONRELEASE flags must be set.
lpszPrefix
[in] The prefix for the filename on which OpenStreamOnFile initializes the IStream object. If set, the prefix must contain not more than three characters. If lpszPrefix is NULL, a prefix of "SOF" is used.
lppStream
[out] Pointer to a pointer to an object exposing the IStream interface.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_NO_ACCESS
The file could not be accessed due to insufficient user permissions or because read-only files cannot be modified.
MAPI_E_NOT_FOUND
The designated file does not exist.

Remarks

The OpenStreamOnFile function has two important uses, distinguished by the setting of the SOF_UNIQUEFILENAME flag. When this flag is not set, OpenStreamOnFile opens an IStream object on an existing file, for example to copy its contents to the PR_ATTACH_DATA_BIN property of an attachment using the IStream::CopyTo method. In this case the lpszFileName parameter specifies the path and filename of the file.

When SOF_UNIQUEFILENAME is set, OpenStreamOnFile creates a temporary file to hold data for an IStream object. For this usage, the lpszFileName parameter can optionally designate the path to the directory where the file is to be created, and the lpszPrefix parameter can optionally specify a prefix for the filename.

When the calling client application or service provider is finished with the IStream object, it should free it by calling the OLE IStream::Release method.

MAPI uses the functions pointed to by lpAllocateBuffer and lpFreeBuffer for most memory allocation and deallocation, in particular to allocate memory for use by client applications when calling object interfaces such as IMAPIProp::GetProps and IMAPITable::QueryRows.

Notes to Callers

The SOF_UNIQUEFILENAME flag is used to create a temporary file with a name unique to the messaging system. If this flag is set, the lpszFileName parameter specifes the path for the temporary file, and the lpszPrefix parameter contains the prefix characters of the filename. The constructed filename is <prefix>HHHH.TMP, where HHHH is a hexadecimal number. If lpszFileName is NULL, the file will be created in the temporary file directory that is returned from the Windows function GetTempPath, or the current directory if no temporary file directory has been designated.

If the SOF_UNIQUEFILENAME flag is not set, lpszPrefix is ignored, and lpszFileName should contain the fully qualified path and filename of the file to be opened or created. The file will be opened or created based on the other flags that are set in ulFlags.

See Also

IStorage Functions


OpenTnefStream

The OpenTnefStream function is called by a transport provider to initiate a MAPI Transport Neutral Encapsulation Format (TNEF) session.

Quick Info

Header file: | TNEF.H
Implemented by: | MAPI
Called by: | Transport providers

HRESULT OpenTnefStream(
  LPVOID lpvSupport,
  LPSTREAM lpStream,
  LPTSTR lpszStreamName,
  ULONG ulFlags,
  LPMESSAGE lpMessage,
  WORD wKey,
  LPITNEF FAR * lppTNEF
);

Parameters

lpvSupport
Passes a support object or passes in NULL. If NULL, the value of the lpadrbook parameter should be non-null.
lpStream
[in] Pointer to a storage stream object — OLE IStream interface — providing a source or destination for a TNEF stream message.
lpszStreamName
[in] Pointer to the name of the data stream that the TNEF object uses. If the caller has set the TNEF_ENCODE flag (ulFlags parameter) in its call to OpenTnefStream, the lpszName parameter must specify a non-null pointer to a non-null string consisting of any characters considered valid for naming a file. MAPI does not allow string names including the characters "[", "]", or ":", even if the file system permits their use. The size of the string passed for lpszName must not exceed the value of MAX_PATH, the maximum length of a string containing a path name.
ulFlags
[in] Bitmask of flags used to indicate the mode of the function. The following flags can be set:
TNEF_BEST_DATA
All possible properties are mapped into their down-level attributes, but when there is a possible data loss due to the conversion to a down-level attribute, the property is also encoded in the encapsulations. Note that this will cause the duplication of information in the TNEF stream. TNEF_BEST_DATA is the default if no other modes are specified.
TNEF_COMPATIBILITY
Ensures backward compatibility with the Microsoft Mail 3.0 client. TNEF streams encoded with this flag will map all possible properties into their corresponding down-level attribute. This mode also causes the defaulting of some properties that are required by down-level clients.
TNEF_DECODE
The TNEF object on the indicated stream is opened with read-only access. The transport provider must set this flag if it wants the function to initialize the object for subsequent decoding.
TNEF_ENCODE
The TNEF object on the indicated stream is opened for read/write access. The transport provider must set this flag if it wants the function to initialize the object for subsequent encoding.
TNEF_PURE
Encodes all properties into the MAPI encapsulation blocks. Therefore, a "pure" TNEF file will consist of, at most, attMAPIProps, attAttachment, attRenddata, and attRecipTable. This mode is ideal for use when no backward compatibility is required.
lpMessage
[in] Pointer to a message object as a destination for a decoded message with attachments or a source for an encoded message with attachments. Any properties of a destination message might be overwritten by the properties of an encoded message.
wKey
[in] A search key that the TNEF object uses to match attachments to the text tags inserted in the message text. This value should be relatively unique across messages.
lppTNEF
[out] Pointer to the new TNEF object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

A TNEF object created by the OpenTnefStream function later calls the OLE method IUnknown::AddRef to add references for the support object, the stream object, and the message object. The transport provider can release the references for all three objects with a single call to the OLE method IUnknown::Release on the TNEF object.

OpenTnefStream allocates and initializes a TNEF object — ITnef interface — for the provider to use in encoding a MAPI message — IMessage interface — into a TNEF stream message. Alternatively, the function can set up the object for the provider to use in subsequent calls to ITnef::ExtractProps to decode a TNEF stream message into a MAPI message. To free the TNEF object and close the session, the transport provider must call the inherited IUnknown::Release method on the object.

A 32-bit Windows program should call OpenTnefStream strictly as defined in the syntax, using the name provided. However, a 16-bit Windows program can set its own name for this function using the OPENTNEFSTREAM function prototype. The prototype has exactly the same syntax as the formal function, except that it designates a return value of HRESULT instead of STDMETHODIMP.

This function is the original entry point for TNEF access and has been replaced by OpenTnefStreamEx but is still used for compatibility for those already using TNEF.

See Also

Tnef Functions, IMAPISupport : IUnknown, IXPProvider::TransportLogon


OpenTnefStreamEx

The OpenTnefStreamEx function creates a TNEF object that can be used to encode or decode a message object into a TNEF data stream for use by transports or gateways and message stores. This is the entry point for TNEF access.

Quick Info

Header file: | TNEF.H
Implemented by: | MAPI
Called by: | Transport providers

HRESULT OpenTnefStreamEx(
  LPVOID lpvSupport,
  LPSTREAM lpStreamName,
  LPTSTR lpszStreamName,
  ULONG ulFlags,
  LPMESSAGE lpMessage,
  WORD wKeyVal,
  LPADRBOOK lpAdressBook,
  LPITNEF FAR * lppTNEF
);

Parameters

lpvSupport
Passes a support object or passes in NULL. If NULL, the lpadrbook parameter should be non-null.
lpStreamName
[in] Pointer to a storage stream object, such as an OLE IStream interface, providing a source or destination for a TNEF stream message.
lpszStreamName
[in] Pointer to the name of the data stream that the TNEF object uses. If the caller has set the TNEF_ENCODE flag (ulFlags parameter) in its call to OpenTnefStream, the lpszName parameter must specify a non-null pointer to a non-null string consisting of any characters considered valid for naming a file. MAPI does not allow string names including the characters "[", "]", or ":", even if the file system permits their use. The size of the string passed for the lpszName parameter must not exceed the value of MAX_PATH, the maximum length of a string containing a path name.
ulFlags
[in] Bitmask of flags used to indicate the mode of the function. The following flags can be set:
TNEF_BEST_DATA
All possible properties are mapped into their down-level attributes, but when there is a possible data loss due to the conversion to a down-level attribute, the property is also encoded in the encapsulations. Note that this will cause the duplication of information in the TNEF stream. TNEF_BEST_DATA is the default if no other modes are specified.
TNEF_COMPATIBILITY
Ensures backward compatibility with the Microsoft Mail 3.0 client. TNEF streams encoded with this flag will map all possible properties into their corresponding down-level attribute. This mode also causes the defaulting of some properties that are required by down-level clients.
TNEF_DECODE
The TNEF object on the indicated stream is opened with read-only access. The transport provider must set this flag if it wants the function to initialize the object for subsequent decoding.
TNEF_ENCODE
The TNEF object on the indicated stream is opened for read/write access. The transport provider must set this flag if it wants the function to initialize the object for subsequent encoding.
TNEF_PURE
Encodes all properties into the MAPI encapsulation blocks. Therefore, a "pure" TNEF file will consist of, at most, the attributes attMAPIProps, attAttachment, attRenddata, and attRecipTable. This mode is ideal for use when no backward compatibility is required.
lpMessage
[in] Pointer to a message object as a destination for a decoded message with attachments or a source for an encoded message with attachments. Any properties of a destination message can be overwritten by the properties of an encoded message.
wKeyVal
[in] A search key that the TNEF object uses to match attachments to the text tags inserted in the message text. This value should be relatively unique across messages.
lpAdressBook
[in] Pointer to an address book object used to get addressing information for entry identifiers.
lppTNEF
[out] Pointer to the new TNEF object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

The OpenTnefStreamEx function is the recommended replacement for OpenTnefStream, the original entry point for TNEF access.

A TNEF object created by the OpenTnefStreamEx function later calls the OLE method IUnknown::AddRef to add references for the support object, the stream object, and the message object. The transport provider can release the references for all three objects with a single call to the OLE method IUnknown::Release on the TNEF object.

OpenTnefStreamEx allocates and initializes a TNEF object for the provider to use in encoding a MAPI message into a TNEF stream message. Alternatively, this function can set up the object for the provider to use in subsequent calls to ITnef::ExtractProps to decode a TNEF stream message into a MAPI message. To free the TNEF object and close the session, the transport provider must call the inherited IUnknown::Release method on the object.

A 32-bit Windows program should call OpenTnefStreamEx strictly as defined in the syntax, using the name provided. However, a 16-bit Windows program can set its own name for this function using the OPENTNEFSTREAM function prototype. The prototype has exactly the same syntax as the formal function, except that it designates a return value of HRESULT instead of STDMETHODIMP.

The base value for the wKeyVal parameter must not be zero and should not be the same for every call to OpenTnefStreamEx. Instead, use random numbers based on the system time from the run-time library's random number generator.

See Also

Tnef Functions, IMAPISupport : IUnknown, IXPProvider::TransportLogon


OPTIONCALLBACK

The OPTIONCALLBACK function prototype defines a callback function that MAPI calls to retrieve a wrapped IMAPIProp interface that manages a transport provider's properties.

Quick Info

Header file: | MAPISPI.H
Defined function implemented by: | Transport providers
Defined function called by: | MAPI

SCODE OPTIONCALLBACK(
  HINSTANCE hInst,
  LPMALLOC lpMalloc,
  ULONG ulFlags,
  ULONG cbOptionData,
  LPBYTE lpbOptionData,
  LPMAPISUP lpMAPISup,
  LPMAPIPROP lpDataSource,
  LPMAPIPROP FAR * lppWrappedSource,
  LPMAPIERROR FAR * lppMAPIError
);

Parameters

hInst
[in] The hinstance value for this transport provider's dynamic-link library (DLL) as returned from the LoadLibrary function call made by MAPI.
lpMalloc
[in] Pointer to a memory allocator object exposing the OLE IMalloc interface. The transport provider may need to use this allocation method when working with certain interfaces such as IStream.
ulFlags
[in] Bitmask of flags that controls what options are processed. The following flags can be set:
OPTION_TYPE_MESSAGE
Message options.
OPTION_TYPE_RECIPIENT
Recipient options.
cbOptionData
[in] Size, in bytes, of the data pointed to by the lpbOptionData parameter.
lpbOptionData
[in] Pointer to an OPTIONDATA structure containing option data for the recipient or message. This OPTIONDATA structure was passed in the call to the IXPLogon::RegisterOptions method that registered the options.
lpMAPISup
[in] Pointer to a MAPI support object the provider can use to call the methods of the IMAPISupport : IUnknown interface.
lpDataSource
[in] Pointer to an IMAPIProp : IUnknown interface that MAPI wraps for the transport provider's use.
lppWrappedSource
[out] Pointer to a pointer to the wrapped IMAPIProp interface returned by the transport provider.
lppMAPIError
[out] Pointer to a pointer to the returned MAPIERROR structure, if any, containing version, component, and context information for the error.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

MAPI calls the transport provider's OPTIONCALLBACK function if a transport provider has previously registered message options with the IXPLogon::RegisterOptions method. Transport providers that do not define message or recipient options do not need to implement this callback function.

MAPI passes a wrapped IMAPIProp : IUnknown interface in the lpDataSource parameter. The transport provider should build a display table, set any properties, and then pass that display table back to MAPI in a wrapped IMAPIProp interface in the lppWrappedSource parameter. MAPI uses this IMAPIProp interface to display properties in the message or recipient options dialog box that is displayed to users. When users make selections in the dialog box resulting in a call to the IMAPIProp::OpenProperty method for the PR_DETAILS_TABLE property, the transport provider gets the call and should display the display table. The transport provider must call the IMAPIProp::SetProps method followed by the IMAPIProp::SaveChanges method on any changes the user made to the display table.

For more information on how to create display tables, see Display Tables.


PpropFindProp

The PpropFindProp function searches for a specified property in a property set.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

PpropFindProp(
  LPSPropValue rgprop,
  ULONG cprop,
  ULONG ulPropTag
);

Parameters

rgprop
[in] Array of SPropValue structures that define the properties to be searched.
cprop
[in] Count of properties in the property set indicated by the rgprop parameter.
ulPropTag
[in] Property tag for the property to search for in the property set indicated by the rgprop parameter.

Remarks

If the given property tag indicates a property of type PT_UNSPECIFIED, the PpropFindProp function finds a match only for the property identifier within the tag. Otherwise, it finds a match for the entire property tag, including the property type, and returns the property so identified.

PpropFindProp returns an SPropValue structure defining the property that matches the input property tag, and NULL if there is no match.

See Also

Properties Functions


PreprocessMessage

The PreprocessMessage function prototype defines a function that preprocesses message contents or the format of a message.

Quick Info

Header file: | MAPISPI.H
Defined function implemented by: | Transport providers
Defined function called by: | MAPI spooler

HRESULT PreprocessMessage(
  LPVOID lpvSession,
  LPMESSAGE lpMessage,
  LPADRBOOK lpAdrBook,
  LPMAPIFOLDER lpFolder,
  LPALLOCATEBUFFER AllocateBuffer,
  LPALLOCATEMORE AllocateMore,
  LPFREEBUFFER FreeBuffer,
  ULONG FAR * lpcOutbound,
  LPMESSAGE FAR * FAR * lpppMessage,
  LPADRLIST FAR * lppRecipList
);

Parameters

lpvSession
[in] Pointer to the session to be used.
lpMessage
[in] Pointer to the message to be preprocessed.
lpAdrBook
[in] Pointer to the address book from which the user should select recipients for the message.
lpFolder
[in, out] Pointer to a folder. On input, the lpFolder parameter points to the folder that contains messages to be preprocessed. On output, lpFolder points to the folder where preprocessed messages have been placed.
lpAllocateBuffer
[in] Pointer to the MAPIAllocateBuffer function, to be used to allocate memory.
lpAllocateMore
[in] Pointer to the MAPIAllocateMore function, to be used to allocate additional memory where required.
lpFreeBuffer
[in] Pointer to the MAPIFreeBuffer function, to be used to free memory.
lpcOutbound
[out] Pointer to the number of messages in the array pointed to by the lpppMessage parameter.
lpppMessage
[out] Pointer to a pointer to an array of pointers to preprocessed or otherwise generated messages.
lppRecipList
[out] Pointer to an optional returned ADRLIST structure, listing preprocessor-detected recipients for which the message is undeliverable. For more information on the contents of this list, see the IMAPISupport::StatusRecips method.

Remarks

A transport-provider message preprocessor can present a progress indicator during message preprocessing. However, it should never present a dialog box requiring user interaction during message preprocessing.

When a preprocessor adds large amounts of data to an outbound message, certain procedures should be followed. This type of message can be stored in a server-based message store, causing the preprocessor to access a remote store, a time-consuming procedure. To avoid having to do so, the preprocessor should have an option that enables it to store data that takes a large amount of space in a local message store and to provide a reference to that local store in the message.

The preprocessor should not release any of the objects originally passed to the PreprocessMessage – based function.

Before the MAPI spooler can call a PreprocessMessage function, the transport provider must have registered the function in a call to the IMAPISupport::RegisterPreprocessor method. After calling a PreprocessMessage function, the spooler cannot continue submitting a message until the function returns.

The MAPI spooler owns the task of submitting messages. This means the original message is never placed in an array of message pointers and that a call to the SubmitMessage methods is never required.

See Also

Preprocessor Functions, IAddrBook : IMAPIProp, IMAPIFolder : IMAPIContainer, IMAPISupport : IUnknown


PropCopyMore

The PropCopyMore function copies a single property value from a source location to a destination location.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE PropCopyMore(
  LPSPropValue lpSPropValueDest,
  LPSPropValue lpSPropValueSrc,
  ALLOCATEMORE * lpfAllocMore,
  LPVOID lpvObject
);

Parameters

lpSPropValueDest
[out] Pointer to the location to which this function writes an SPropValue structure defining the copied property value.
lpSPropValueSrc
[in] Pointer to the SPropValue structure containing the property value to be copied.
lpfAllocMore
[in] Pointer to the MAPIAllocateMore function to be used to allocate additional memory if the destination location is not large enough to hold the property to be copied.
lpvObject
[in] Pointer to an object for which MAPIAllocateMore will allocate space if necessary.

Remarks

A client application or service provider can use the PropCopyMore function to copy a property out of a table that is about to be freed in order to use it elsewhere.

PropCopyMore does not need to allocate memory unless the property value copied is of a type, such as PT_STRING8, that does not fit in an SPropValue structure. For these large properties, the function allocates memory using the MAPIAllocateMore function to which a pointer is passed in the lpfAllocMore parameter.

Injudicious use of PropCopyMore fragments memory; consider using the ScCopyProps function instead.

See Also

Properties Functions


RemovePreprocessInfo

The RemovePreprocessInfo function prototype defines a function that removes from a message preprocessed information written by a PreprocessMessage based function.

Quick Info

Header file: | MAPISPI.H
Defined function implemented by: | Transport providers
Defined function called by: | MAPI spooler

HRESULT RemovePreprocessInfo(
  LPMESSAGE lpMessage
);

Parameters

lpMessage
[in] Pointer to the preprocessed message from which information is to be removed.

Remarks

The MAPI spooler calls a function based on RemovePreprocessInfo. A transport provider registers the RemovePreprocessInfo – based function at the same time it registers the parallel PreprocessMessage – based function in a call to the IMAPISupport::RegisterPreprocessor method.

An image rendering suitable for fax transmission is an example of preprocessed information written by a function defined by the PreprocessMessage function prototype. The MAPI spooler usually calls a RemovePreprocessInfo function after sending a message containing preprocessed information.

See Also

Preprocessor Functions


RTFSync

The RTFSync function ensures that the Rich Text Format (RTF) message text matches the plain text version. It is necessary to call this function before reading the RTF version and after modifying the RTF version.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | RTF-aware client applications and message store providers

HRESULT RTFSync(
  LPMESSAGE lpMessage,
  ULONG ulFlags,
  BOOL FAR * lpfMessageUpdated
);

Parameters

lpMessage
[in] Pointer to the message to be updated.
ulFlags
[in] Bitmask of flags used to indicate the RTF or plain text version of the message has changed. The following flags can be set:
RTF_SYNC_BODY_CHANGED
The plain text version of the message has changed.
RTF_SYNC_RTF_CHANGED
The RTF version of the message has changed.

All other bits in the ulFlags parameter are reserved for future use.

lpfMessageUpdated
[out] Pointer to a variable indicating whether there is an updated message. TRUE if there is an updated message, FALSE otherwise.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

If the PR_RTF_IN_SYNC property is missing or is FALSE, before reading the PR_RTF_COMPRESSED property the RTFSync function should be called with the RTF_SYNC_BODY_CHANGED flag set.

If the STORE_RTF_OK flag is not set in the PR_STORE_SUPPORT_MASK property, this function should be called with the RTF_SYNC_RTF_CHANGED flag set after modifying PR_RTF_COMPRESSED.

If both PR_BODY and PR_RTF_COMPRESSED have been changed, the RTFSync function should be called with both flags set.

If the value of the lpfMessageUpdated parameter is set to TRUE, then the IMAPIProp::SaveChanges method should be called for the message. If SaveChanges is not called, the modifications will not be saved in the message.

Message store providers can use RTFSync to keep the PR_BODY and PR_RTF_COMPRESSED properties synchronized.

For more information, see Supporting RTF Text for Message Store Providers.

See Also

RTF Synchronization Functions, WrapCompressedRTFStream


ScBinFromHexBounded

The ScBinFromHexBounded function converts the specified portion of a string representation of a hexadecimal number into a binary number.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE ScBinFromHexBounded(
  LPTSTR sz,
  LPBYTE pb,
  ULONG cb
);

Parameters

sz
[in] Pointer to the null-terminated string to be converted. Valid characters include the hexadecimal characters 0 through 9 and both uppercase and lowercase characters a through f.
pb
[out] Pointer to the returned binary number.
cb
[in] Size, in bytes, of the pb parameter.

See Also

String Operation Functions, FBinFromHex


ScCopyNotifications

The ScCopyNotifications function copies a group of event notifications to a single block of memory.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE ScCopyNotifications(
  int cntf,
  LPNOTIFICATION rgntf,
  LPVOID pvDst,
  ULONG FAR * pcb
);

Parameters

cntf
[in] Count of NOTIFICATION structures in the array indicated by the rgntf parameter.
rgntf
[in] Pointer to an array of NOTIFICATION structures defining the event notifications to be copied.
pvDst
[out] Pointer to the returned notifications.
pcb
[out] Optional pointer to a variable where the size, in bytes, of the array pointed to by the rgntf parameter is stored. If not NULL, the pcb parameter is set to the number of bytes stored in the pvDst parameter.

Remarks

If NULL is passed in the pcb parameter, no copying is performed; if a non-null value is passed in pcb, the ScCopyNotifications function copies the size of the array and the array itself to a single block of memory. If pcb is not NULL, it is set to the number of bytes stored in the pvDst parameter. The pvDst parameter must be large enough to contain the entire array.

See Also

Notification Functions


ScCopyProps

The ScCopyProps function copies the properties defined by an array of SPropValue structures to a new destination.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE ScCopyProps(
  int cprop,
  LPSPropValue rgprop,
  LPVOID pvDst,
  ULONG FAR * pcb
);

Parameters

cprop
[in] Count of properties to be copied.
rgprop
[in] Pointer to an array of SPropValue structures that define the properties to be copied. The rgprop parameter need not point to the beginning of the array, but it must point to the beginning of one of the SPropValue structures in the array.
pvDst
[in] Pointer to the initial position in memory to which this function copies the properties.
pcb
[out] Optional pointer to the size, in bytes, of the block of memory pointed to by the pvDst parameter.

Remarks

The new array and its data reside in a buffer created with a single allocation, and the ScRelocProps function can be used to adjust the pointers in the individual SPropValue structures. Prior to this adjustment, the pointers are valid.

ScCopyProps maintains the original property order for the copied property array.

The pcb parameter is optional; if it is not NULL, it is set to the number of bytes stored in the pvDst parameter.

See Also

Properties Functions, ScDupPropset


ScCountNotifications

The ScCountNotifications function determines the size, in bytes, of an array of event notifications, and validates the memory associated with the array.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE ScCountNotifications(
  int cntf,
  LPNOTIFICATION rgntf,
  ULONG FAR * pcb
);

Parameters

cntf
[in] Count of NOTIFICATION structures in the array indicated by the rgntf parameter.
rgntf
[in] Pointer to the array of NOTIFICATION structures whose size is to be determined.
pcb
[out] Optional pointer to the size, in bytes, of the array pointed to by the rgntf parameter. If NULL, ScCountNotifications validates the array of notifications.

Remarks

If NULL is passed in the pcb parameter, the ScCountNotifications function only validates the array of notifications but no counting is done; if a non-null value is passed in pcb, ScCountNotifications determines the size of the array and stores the result in pcb. The pcb parameter must be large enough to contain the entire array.

See Also

Notification Functions


ScCountProps

The ScCountProps function determines the size, in bytes, of a property value array and validates the memory associated with the array.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE ScCountProps(
  int cprop,
  LPSPropValue rgprop,
  ULONG FAR * pcb
);

Parameters

cprop
[in] Count of properties in the array indicated by the rgprop parameter.
rgprop
[in] Pointer to a range in an array of SPropValue structures that defines the properties whose size is to be determined. This range does not necessarily start at the beginning of the array.
pcb
[out] Optional pointer to the size, in bytes, of the property array.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_INVALID_PARAMETER
At least one property in the property value array has an identifier of PROP_ID_NULL or PROP_ID_INVALID, or the property array contains a multivalued property with no property values.

Remarks

If NULL is passed in the pcb parameter, the ScCountProps function validates the array of notifications but no counting is done. If a non-null value is passed in pcb, the ScCountNotifications function determines the size of the array and stores the result in pcb. The pcb parameter must be large enough to contain the entire array.

As it is counting, ScCountProps validates the memory associated with the array. ScCountProps only works with properties about which MAPI has information.

See Also

Properties Functions, PropCopyMore


ScCreateConversationIndex

The ScCreateConversationIndex function indicates where in a message thread a message belongs.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE ScCreateConversationIndex(
  ULONG cbParent,
  LPBYTE lpbParent,
  ULONG FAR* lpcbIndex,
  LPBYTE FAR * lppbIndex
);

Parameters

cbParent
[in] Count of bytes in the parent conversation index.
lpbParent
[in] Pointer to bytes in the parent conversation index. This may be NULL if cbParent is zero.
lpcbIndex
[out] Pointer to the count of bytes in the new conversation index returned by the call.
lppbIndex
[out] Pointer to a pointer to the new conversation index returned by the call.

Return Values

S_OK
The call succeeded and has returned the expected value or values.


ScDupPropset

The ScDupPropset function duplicates a property value array in a single block of MAPI memory combining the operations of the ScCopyProps and ScCountProps functions.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE ScDupPropset(
  int cprop,
  LPSPropValue rgprop,
  LPALLOCATEBUFFER lpAllocateBuffer,
  LPSPropValue FAR * prgprop
);

Parameters

cprop
[in] Count of property values in the array indicated by the rgprop parameter.
rgprop
[in] Pointer to an array of SPropValue structures defining the property values to be duplicated.
lpAllocateBuffer
[in] Pointer to the MAPIAllocateBuffer function, to be used to allocate memory for the duplicated array.
prgprop
[out] Pointer to the initial position in memory where the returned duplicated array of SPropValue structures is stored.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

See Also

Properties Functions


ScInitMapiUtil

The ScInitMapiUtil function replaces MAPIInitialize when only select utility functions are being used.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications

SCODE ScInitMapiUtil(
  ULONG ulFlags
);

Parameters

ulFlags
Reserved; must be zero.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

The ScInitMapiUtil and DeinitMapiUtil functions cooperate to call and release select utility functions, as opposed to MAPIInitialize, which calls core as well as utility functions. When ScInitMapiUtil calls utility functions, it also initializes the necessary memory.

When use of the functions that ScInitMapiUtil has called is complete, DeinitMapiUtil must be explicitly called to release them. In contrast, MAPIInitialize implicitly calls DeinitMapiUtil.

See Also

MapiUninitialize


ScLocalPathFromUNC

The ScLocalPathFromUNC function locates a local path counterpart to the given universal naming convention (UNC) path.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE ScLocalPathFromUNC(
  LPSTR szUNC,
  LPSTR szLocal,
  UINT cchLocal
);

Parameters

szUNC
[in] A path in the format \\[server]\[share]\[path] of a file or directory.
szLocal
[out] A path in the format [drive:]\[path] of the same file or directory as for the szUNC parameter.
cchLocal
[in] Size of the buffer for the output string.

See Also

Path Name Functions, ScUNCFromLocalPath


ScMAPIXFromCMC

The ScMAPIXFromCMC function enables a client application to pass in a CMC session handle and get back a pointer to a MAPI session object.

Quick Info

Header file: | MAPI.H
Implemented by: | MAPI
Called by: | Client applications

SCODE ScMAPIXFromCMC(
  CMC_SESSION cmcsession,
  ULONG ulFlags,
  LPCIID lpInterface,
  LPMAPISESSION FAR * lppMAPISession
);

Parameters

cmcsession
[in] Pointer to the CMC session in use.
ulFlags
Reserved; must be zero.
lpInterface
[in] The MAPI interface being returned.
lppMAPISession
[out] Pointer to the pointer to the MAPI session in use.

Return Values

S_OK
The call succeeded and converted the CMC session to a MAPI session.

Remarks

There are no inverse functions for either the ScMAPIXFromCMC or ScMAPIXFromSMAPI function, that is, a client cannot convert to a CMC session or Simple MAPI session from a MAPI session. Also, a client cannot convert from a CMC session to a Simple MAPI session.

For more information on this function, see Using Multiple Client Interfaces and Explicit Logon with Simple MAPI.


ScMAPIXFromSMAPI

The ScMAPIXFromSMAPI function enables a client application to pass in a Simple MAPI session handle and get back a pointer to a MAPI session object.

Quick Info

Header file: | MAPI.H
Implemented by: | MAPI
Called by: | Client applications

SCODE ScMAPIXFromSMAPI(
  LHANDLE lhSimpleSession,
  ULONG ulFlags,
  LPCIID lpInterface,
  LPMAPISESSION FAR * lppMAPISession
);

Parameters

lhSimpleSession
[in] Pointer to a Simple MAPI session.
ulFlags
Reserved; must be zero.
lpInterface
[in] The MAPI interface to be returned.
lppMAPISession
[out] Pointer to a variable where a pointer for a specific MAPI session is stored.

Return Values

S_OK
The call succeeded and has converted the Simple MAPI session to a MAPI session.

Remarks

There are no inverse functions for either the ScMAPIXFromCMC or ScMAPIXFromSMAPI function, that is, a client cannot convert to a CMC session or Simple MAPI session from a MAPI session. Also, a client cannot convert from a Simple MAPI session to a CMC session.

For more information on using this function, see Using Multiple Client Interfaces and Explicit Logon with Simple MAPI.


ScRelocNotifications

The ScRelocNotifications function adjusts a pointer within a specified event notification array.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE ScRelocNotifications(
  int cntf,
  LPNOTIFICATION rgntf,
  LPVOID pvBaseOld,
  LPVOID pvBaseNew,
  ULONG FAR * pcb
);

Parameters

cntf
[in] Count of NOTIFICATION structures in the array indicated by the rgntf parameter.
rgntf
[in] Pointer to the array of NOTIFICATION structures defining event notifications within which a pointer is to be adjusted.
pvBaseOld
[in] Pointer to the original base address of the array indicated by the rgntf parameter.
pvBaseNew
[in] The location to which ScRelocNotifications writes the new base address of the array indicated by the rgntf parameter.
pcb
[out] Pointer to the size, in bytes, of the array indicated by the pvBaseNew parameter.

Remarks

The pcb parameter to the ScRelocNotifications function is optional.

See Also

Notification Functions, ScRelocProps


ScRelocProps

The ScRelocProps function adjusts the pointers in an SPropValue array after the array and its data have been copied or moved to a new location.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE ScRelocProps(
  int cprop,
  LPSPropValue rgprop,
  LPVOID pvBaseOld,
  LPVOID pvBaseNew,
  ULONG FAR * pcb
);

Parameters

cprop
[in] Count of properties in the array pointed to by the rgprop parameter.
rgprop
[in] Pointer to an array of SPropValue structures for which pointers are to be adjusted.
pvBaseOld
[in] Pointer to the original base address of the array pointed to by the rgprop parameter.
pvBaseNew
[in] Pointer to the new base address of the array pointed to by the rgprop parameter.
pcb
[in, out] Optional pointer to the size, in bytes, of the array indicated by the pvBaseNew parameter. If not NULL, the pcb parameter is set to the number of bytes stored in the pvD parameter.

Remarks

The ScRelocProps function operates on the assumption that the property value array for which pointers are adjusted was originally allocated in a single call similar to a call to the ScCopyProps function. If a client application or service provider is working with a property value that is built from disjointed blocks of memory, it should use ScCopyProps to copy properties instead.

ScRelocProps is used to maintain the validity of pointers in an SPropValue array. To maintain pointers' validity when writing such an array to and reading it from a disk, perform the following operations:

  1. Before writing the array and data to a disk, call ScRelocProps on the array with the pvBaseNew parameter pointing to some standard value — zero, for instance.
  2. After reading the array and data from a disk, call ScRelocProps on the array with the pvBaseOld parameter equal to the same standard value used in Step 1. The array and data must be read into a buffer created with a single allocation.
  3. The pcb parameter to ScRelocProps is optional.

See Also

Properties Functions, MAPIAllocateBuffer, ScCountProps, ScDupPropset, SCRelocNotifications


ScUNCFromLocalPath

The ScUNCFromLocalPath function locates a universal naming convention (UNC) path counterpart to the given local path.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

SCODE ScUNCFromLocalPath(
  LPSTR szLocal,
  LPSTR szUNC,
  UINT cchUNC
);

Parameters

szLocal
[in] A path in the format [drive:]\[path] of a file or directory.
szUNC
[out] A path in the format \\[server]\[share]\[path] of the same file or directory as for the szLocal parameter.
cchUNC
[in] Size of the buffer for the output string.

See Also

Path Name Functions, ScLocalPathFromUNC


SERVICEWIZARDDLGPROC

The SERVICEWIZARDDLGPROC function prototype defines a callback function invoked by the Profile Wizard to allow a service provider to react to user events when the provider's property sheets or pages are being shown.

Quick Info

Header file: | MAPIWZ.H
Defined function implemented by: | Service providers
Defined function called by: | MAPI Profile Wizard

BOOL SERVICEWIZARDDLGPROC(
  HWND hDlg,
  UINT wMsgID,
  WPARAM wParam,
  LPARAM lParam
);

Parameters

hDlg
[in] Window handle to the Profile Wizard dialog box.
wMsgID
[in] The window message to be processed. In addition to the regular window messages expected by a modal dialog box, the following messages can be received:
WM_CLOSE
The Profile Wizard has completed. The service provider should do all required cleanup such as deallocating any dynamically allocated memory.
WM_COMMAND
One of the provider's controls has been selected, or the Next or Back button has been clicked. The value in the wParam parameter indicates which of these user events has occurred.
WM_INITDIALOG
The user has moved to another property page, for which the dialog box must be initialized. The provider should initialize the controls that the Profile Wizard has added to the dialog box.
WIZ_QUERYNUMPAGES
The Profile Wizard is prompting for the number of pages that the provider needs to display. The provider should return the number of pages instead of TRUE or FALSE. For example, use the following return statement to indicate that three pages should to be displayed:
return (BOOL)3;
wParam
[in] A 32-bit parameter associated with window messages. Possible values depend on the message specified in the wMsgID parameter. In addition to the values expected with the regular window messages for a modal dialog box, the following values can be received:
WIZ_NEXT
When wMsgID contains WM_COMMAND, the user has clicked the Next button.
WIZ_PREV
When wMsgID contains WM_COMMAND, the user has clicked the Back button.
lParam
[in] A 32-bit parameter associated with window messages. Possible values depend on the message specified in the wMsgID parameter.

Return Values

The value returned by a SERVICEWIZARDDLGPROC – based function is dependent on the window message received. Note in particular the exceptional return value for the WIZ_QUERYNUMPAGES message. The normal return values are:

TRUE
The service provider has processed the received window message.
FALSE
The service provider has not processed the received window message.

Remarks

When the user moves from one property page to another, the provider is responsible for hiding the old page's controls and showing the controls for the next or previous page. When the user clicks the Next button, the SERVICEWIZARDDLGPROC – based function is called with the WM_COMMAND message and WIZ_NEXT in the wParam parameter. The following steps describe what occurs between the time the user clicks Next and the time the first provider's configuration pages are rendered.

  1. The Profile Wizard hides any controls that are on the window.
  2. The Profile Wizard adds the provider's hidden controls to the page.
  3. The Profile Wizard calls SERVICEWIZARDDLGPROC, sending the WM_INITDIALOG message, so that the provider can initialize the controls.
  4. The Profile Wizard calls SERVICEWIZARDDLGPROC, sending the WIZ_QUERYNUMPAGES message. The provider returns the number of pages that are to be shown.
  5. The Profile Wizard calls SERVICEWIZARDDLGPROC, sending the WM_COMMAND message with the wParam parameter set to either WIZ_NEXT or WIZ_PREV. At this point, the provider either returns FALSE {error} or reveals its controls and returns TRUE {success}. If the Profile Wizard passes in ID_NEXT, the provider's first page is displayed. If ID_PREV is passed in, the last page is displayed.
  6. The Profile Wizard calls the provider's SERVICEWIZARDDLGPROC function, sending the WM_COMMAND message with the wParam parameter set to either WIZ_NEXT or WIZ_PREV (depending on which button the user clicked). The provider is responsible for showing or hiding its controls and writing its data to the IMAPIProp passed to the Profile Wizard to step through its sequence of pages. The provider should return TRUE if the next or previous page was successfully shown, and FALSE if neither the next nor previous page could be shown. The provider needs to be aware of when it is stepping outside of its sequence of pages, and respond appropriately by hiding its controls and writing its data to the profile.
  7. If the user steps outside the provider's range of pages, the Profile Wizard deletes the provider's hidden controls from the dialog box and calls the next provider — or displays its next page if that was the last provider.

See Also

Profile Wizard Functions


SetAttribIMsgOnIStg

The SetAttribIMsgOnIStg function sets or alters attributes of properties on an IMessage object supplied by the OpenIMsgOnIStg function.

Quick Info

Header file: | IMESSAGE.H
Implemented by: | MAPI
Called by: | Client applications and message store providers

HRESULT SetAttribIMsgOnIStg(
  LPVOID lpObject,
  LPSPropTagArray lpPropTags,
  LPSPropAttrArray lpPropAttrs,
  LPSPropProblemArray FAR * lppPropProblems
);

Parameters

lpObject
[in] Pointer to the object for which property attributes are being set.
lpPropTags
[in] Pointer to an SPropTagArray structure containing an array of property tags indicating the properties for which property attributes are being set.
lpPropAttrs
[in] Pointer to an SPropAttrArray structure listing the property attributes to set.
lppPropProblems
[out] Pointer to the returned SPropProblemArray structure containing a set of property problems. This structure identifies problems encountered if SetAttribIMsgOnIStg has been able to set some properties, but not all. If a pointer to NULL is passed in the lppPropProblems parameter, no property problem array is returned even if some properties were not set.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_W_ERRORS_RETURNED
The call succeeded overall, but one or more properties could not be accessed and were returned with a property type of PT_ERROR.

Remarks

Property attributes can only be accessed on property objects, that is, objects implementing the IMAPIProp : IUnknown interface. To make MAPI properties available on an OLE structured storage object, OpenIMsgOnIStg builds an IMessage : IMAPIProp object on top of the OLE IStorage object. The property attributes on such objects can be set or altered with SetAttribIMsgOnIStg and retrieved with GetAttribIMsgOnIStg.

Note GetAttribIMsgOnIStg and SetAttribIMsgOnIStg do not operate on all IMessage objects. They are only valid for IMessage-on-IStorage objects returned by OpenIMsgOnIStg.

In the lpPropAttrs parameter, the number and position of the attributes must match the number and position of the property tags passed in the lpPropTags parameter.

The SetAttribIMsgOnIStg function is used to make message properties read-only when required by the IMessage schema. The sample message store provider uses it for this purpose. For more information, see Messages.

See Also

IMessage-On-IStorage Functions


SzFindCh

The SzFindCh function searches for the first occurrence of a character in a null-terminated string.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

LPTSTR SzFindCh(
  LPCTSTR lpsz,
  USHORT ch
);

Parameters

lpsz
[in] Pointer to the null-terminated string to be searched.
ch
[in] The character to be searched for.

Return Values

SzFindCh returns a pointer to the first occurrence of the character in the string. If the character does not occur anywhere in the string, or if the lpsz parameter is NULL, a value of NULL is returned.

Remarks

The SzFindCh function searches for an exact match only; it is sensitive to case and diacritical differences. Searches in the Unicode and DBCS formats are supported.

See Also

String Operation Functions


SzFindLastCh

The SzFindLastCh function searches for the last occurrence of a character in a null-terminated string.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

LPTSTR SzFindLastCh(
  LPCTSTR lpsz,
  USHORT ch
);

Parameters

lpsz
[in] Pointer to the null-terminated string to be searched.
ch
[in] The character to be searched for.

Return Values

SzFindLastCh returns a pointer to the last occurrence of the character in the string. If the character does not occur anywhere in the string, or if the lpsz parameter is NULL, a value of NULL is returned.

Remarks

The SzFindLastCh function searches for an exact match only; it is sensitive to case and diacritical differences. Searches in the Unicode and DBCS formats are supported.

See Also

String Operation Functions


SzFindSz

The SzFindSz function searches for the first occurrence of a null-terminated substring in a null-terminated string.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

LPTSTR SzFindCh(
  LPCTSTR lpsz,
  LPCTSTR lpszKey
);

Parameters

lpsz
[in] Pointer to the null-terminated string to be searched. The lpsz parameter must not exceed 65536 characters.
lpszKey
[in] Pointer to the null-terminated substring to be searched for. The lpszKey parameter must not exceed 65536 characters.

Return Values

SzFindSz returns a pointer to the first character of the first occurrence of the substring in the string. If the substring does not occur anywhere in the string, if lpszKey is larger than lpsz, or if either parameter is NULL, a value of NULL is returned.

Remarks

The SzFindSz function searches for an exact match only; it is sensitive to case and diacritical differences. Searches in the Unicode and DBCS formats are supported. The length limit on both parameters is in characters, not necessarily bytes.

See Also

String Operation Functions


UFromSz

The UFromSz function converts a null-terminated string of decimal digits into an unsigned integer.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

UINT UFromSz(
  LPCTSTR lpsz
);

Parameters

lpsz
[in] Pointer to the null-terminated string to be converted. The lpsz parameter must not exceed 65536 characters.

Return Values

UFromSz returns an unsigned integer. If the string does not begin with at least one decimal digit, a binary zero is returned.

Remarks

The UFromSz function stops converting when it reaches the first character in the string that is not a decimal digit. For example, given the string "55", UFromSz returns the integer value 55. Given the string "5a5b", the function returns the integer value 5. Given the string "a5b5", UFromSz returns zero.

UFromSz is sensitive to diacritical differences. Strings in the Unicode and DBCS formats are supported. The length limit on lpsz is in characters, not necessarily bytes.

See Also

String Operation Functions


UlFromSzHex

The UlFromSzHex function converts a null-terminated string of hexadecimal digits into an unsigned long integer.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

ULONG UlFromSzHex(
  LPCTSTR lpsz
);

Parameters

lpsz
[in] Pointer to the null-terminated string to be converted. The lpsz parameter must not exceed 65536 characters.

Return Values

UlFromSzHex returns an unsigned long integer. If the string does not begin with at least one hexadecimal digit, a binary zero is returned.

Remarks

The UlFromSzHex function stops converting when it reaches the first character in the string that is not a hexadecimal digit. For example, given the string "5a", UlFromSzHex returns the integer value 90. Given the string "5g5h", the function returns the integer value 5. Given the string "g5h5", UlFromSzHex returns zero.

UlFromSzHex is sensitive to diacritical differences but allows both 'a' through 'f' and 'A' through 'F' for hexadecimal digits. Strings in the Unicode and DBCS formats are supported. The length limit on lpsz is in characters, not necessarily bytes.

See Also

String Operation Functions


UlAddRef

The UlAddRef function provides an alternative way to invoke the OLE method IUnknown::AddRef.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

ULONG UlAddRef(
  LPVOID punk
);

Parameters

punk
[in] Pointer to an interface derived from the IUnknown interface, in other words any MAPI interface.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_CALL_FAILED
An error of unexpected or unknown origin prevented the operation from completing.

Remarks

The UlAddRef function generates less code than the AddRef method and can be used in situations requiring a minimum of code.

UlAddRef returns the value returned by the IUnknown::AddRef method, which is the new value of the reference count for the interface. The value is nonzero.

For more information on IUnknown::AddRef, see Implementing the IUnknown Interface.

See Also

IUnknown Functions


UlPropSize

The UlPropSize function obtains the size of a single property value.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

ULONG UlPropSize(
  LPSPropValue lpSPropValue
);

Parameters

lpSPropValue
[in] Pointer to an SPropValue structure defining the property to be measured.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_CALL_FAILED
An error of unexpected or unknown origin prevented the operation from completing.

Remarks

The UlPropSize function returns the size, in bytes, of the property value for the specified property. It disregards the size of the remainder of the SPropValue structure.

See Also

Properties Functions


UlRelease

The UlRelease function provides an alternative way to invoke the OLE method IUnknown::Release.

Note This function may not be supported in future versions of MAPI.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

ULONG UlRelease(
  LPVOID punk
);

Parameters

punk
[in] Pointer to an interface derived from the IUnknown interface, in other words any MAPI interface.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_CALL_FAILED
An error of unexpected or unknown origin prevented the operation from completing.

Remarks

The reference count is the number of existing pointers to the object to be released.

If the punk parameter is NULL, the function returns immediately without calling IUnknown::Release. This feature can save code if a client or provider declares an interface pointer and initializes it to NULL. Code is used in the method indication but saved in not testing for NULL.

UlRelease returns the value returned by the IUnknown::Release method, which can be equal to the reference count for the object to be released.

For more information on IUnknown::Release, see Implementing the IUnknown Interface.

See Also

IUnknown Functions


UlValidateParameters

The UlValidateParameters macro calls an internal function to check the parameters client applications have passed to service providers and MAPI.

Quick Info

Header file: | MAPIVAL.H
Implemented by: | MAPI
Called by: | Service providers

HRESULT UlValidateParameters(
  METHODS eMethod,
  LPVOID First
);

Parameters

eMethod
[in] Specifies, by enumeration, the method to validate.
First
[in] Pointer to the first argument on the stack.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_CALL_FAILED
An error of unexpected or unknown origin prevented the operation from completing.

Remarks

The UlValidateParameters macro has been superseded by the UlValidateParms macro. UlValidateParameters does not work correctly on RISC platforms and is now prevented from compiling on them. It still compiles and works correctly on Intel platforms, but UlValidateParms is recommended on all platforms.

See Also

Parameter Validation Macros


UlValidateParms

The UlValidateParms macro calls an internal function to check the parameters client applications have passed to service providers and MAPI.

Quick Info

Header file: | MAPIVAL.H
Implemented by: | MAPI
Called by: | Service providers

HRESULT UlValidateParms(
  METHODS eMethod,
  LPVOID First
);

Parameters

eMethod
[in] Specifies, by enumeration, the method to validate.
First
[in] Pointer to the first argument on the stack.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_CALL_FAILED
An error of unexpected or unknown origin prevented the operation from completing.

Remarks

Parameters passed between MAPI and service providers are assumed to be correct and undergo only debug validation with the CheckParms macro. Providers should check all parameters passed in by client applications, but clients should assume that MAPI and provider parameters are correct. Use the HR_FAILED macro to test return values.

The UlValidateParms macro is called differently depending on whether the calling code is C or C++. This macro is used to validate parameters for the few IUnknown and MAPI methods that return ULONG rather than HRESULT values; the ValidateParms macro works for all others.

For more information on parameter validation, see Validating Parameters to Interface Methods.

See Also

Parameter Validation Macros


ValidateParameters

The ValidateParameters macro calls an internal function to check the parameters client applications have passed to service providers.

Quick Info

Header file: | MAPIVAL.H
Implemented by: | MAPI
Called by: | Service providers

HRESULT ValidateParameters(
  METHODS eMethod,
  LPVOID First
);

Parameters

eMethod
[in] Specifies, by enumeration, the method to validate.
First
[in] Pointer to the first argument on the stack.

Return Values

S_OK
All of the parameters are valid.
MAPI_E_CALL_FAILED
One or more of the parameters are not valid.

Remarks

The ValidateParameters macro has been superseded by the ValidateParms macro. ValidateParameters does not work correctly on RISC platforms and is now prevented from compiling on them. It still compiles and works correctly on Intel platforms, but ValidateParms is recommended on all platforms.

See Also

Parameter Validation Macros


ValidateParms

The ValidateParms macro calls an internal function to check the parameters client applications have passed to service providers.

Quick Info

Header file: | MAPIVAL.H
Implemented by: | MAPI
Called by: | Service providers

HRESULT ValidateParms(
  METHODS eMethod,
  LPVOID First
);

Parameters

eMethod
[in] Specifies, by enumeration, the method to validate.
First
[in] Pointer to the first argument on the stack.

Return Values

S_OK
All of the parameters are valid.
MAPI_E_CALL_FAILED
One or more of the parameters are not valid.

Remarks

Parameters passed between MAPI and service providers are assumed to be correct and undergo only debug validation with the CheckParms macro. Providers should check all parameters passed in by client applications, but clients should assume that MAPI and provider parameters are correct. Use the HR_FAILED macro to test return values.

ValidateParms is called differently depending on whether the calling code is C or C++. C++ passes an implicit parameter known as this to each method call, which becomes explicit in C and is the address of the object. The first parameter, eMethod, is an enumerator made from the interface and method being validated and tells what parameters to expect to find on the stack. The second parameter is different for C and C++. In C++ it is called First, and it is the first parameter to the method being validated. The second parameter for the C language, ppThis, is the address of the first parameter to the method which is always an object pointer. In both cases, the second parameter gives the address of the beginning of the method's parameter list, and based on eMethod, moves down the stack and validates the parameters.

Providers implementing common interfaces such as IMAPITable and IMAPIProp should always check parameters using the ValidateParms function in order to ensure consistency across all providers. Additional parameter validation functions have been defined for some complex parameter types to be used instead as appropriate. See the reference topics for the following functions:

FBadColumnSet

FBadEntryList

FBadProp

FBadPropTag

FBadRestriction

FBadRglpNameID

FBadRglpszW

FBadRow

FBadRowSet

FBadSortOrderSet

Inherited methods use the same parameter validation as the interface from which they inherit. For example, the parameter checking for IMessage and IMAPIProp should be the same.

For more information on parameter validation, see Validating Parameters to Interface Methods.

See Also

Parameter Validation Macros, UlValidateParms


WIZARDENTRY

The WIZARDENTRY function prototype defines a service provider entry point function which the Profile Wizard calls to retrieve enough information to display the provider's configuration property sheets.

Quick Info

Header file: | MAPIWZ.H
Defined function implemented by: | Service providers
Defined function called by: | MAPI Profile Wizard

ULONG WIZARDENTRY(
  HINSTANCE hProviderDLLInstance,
  LPTSTR FAR * lpcsResourceName,
  DLGPROC FAR * lppDlgProc,
  LPMAPIPROP lpMAPIProp,

   );

Parameters

hProviderDLLInstance
[in] Instance handle of the service provider's DLL.
lpcsResourceName
[out] Pointer to a string containing the full name of the dialog resource that should be displayed by the Profile Wizard during configuration. The maximum size of the string, including the NULL terminator, is 32 characters.
lppDlgProc
[out] Pointer to a standard Windows dialog box procedure that will be called by the Profile Wizard to notify the provider of various events.
lpMapiProp
[in] Pointer to a property interface implementation that provides access to the configuration properties.
lpMapiSupportObject
[in] Pointer to the MAPI support object applicable to this session.

Return Values

S_OK
The service provider's WIZARDENTRY function was called successfully.
MAPI_E_CALL_FAILED
An error of unexpected or unknown origin prevented the operation from completing.

Remarks

The Profile Wizard calls the WIZARDENTRY based function when it is ready to display the service provider's configuration user interface. When the Profile Wizard is finished configuring all providers, it writes the configuration properties to the profile by calling IMsgServiceAdmin::ConfigureMsgService.

Notes to Implementers

The name of the WIZARDENTRY – based function must be placed in the WIZARD_ENTRY_NAME entry in MAPISVC.INF.

The resource name is that of the dialog resource that will be rendered in the pane of the Profile Wizard. The resource that is passed back needs to contain all the pages — in a single dialog resource — that should be displayed by the Profile Wizard. When the Profile Wizard receives this resource, it ignores the dialog style, but not the control styles, and creates all the controls as children of the Profile Wizard page. All controls are initially hidden. Providers should ensure that the coordinates for their controls are zero or zero-based, and that they do not exceed a maximum width of 200 dialog units and a maximum height of 150 dialog units. Control identifiers below 400 are reserved for the Profile Wizard. The Profile Wizard displays the provider's title in bold text above the provider's user interface.

The property interface pointer supplied in the lpMapiProp parameter should be retained by the provider for future reference. The Profile Wizard deals with only the most basic set of properties, and the provider can use the property interface implementation to include additional properties. During configuration, providers should add their configuration properties to the object implementing the property interface. After all providers have been configured, the Profile Wizard adds these properties to the profile.

For more information on using this function, see Supporting Message Service Configuration.

See Also

Profile Wizard Functions


WrapCompressedRTFStream

The WrapCompressedRTFStream function creates a text stream in uncompressed Rich Text Format (RTF) from the compressed format used in the PR_RTF_COMPRESSED property.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications

HRESULT WrapCompressedRTFStream(
  LPSTREAM lpCompressedRTFStream,
  ULONG ulflags,
  LPSTREAM FAR * lpUncompressedRTFStream
);

Parameters

lpCompressedRTFStream
[in] Pointer to a stream opened on the PR_RTF_COMPRESSED property of a message.
ulFlags
[in] Bitmask of option flags for the function. The following flags can be set:
MAPI_MODIFY
Whether the client intends to read or write the wrapped stream interface that is returned.
STORE_UNCOMPRESSED_RTF
Uncompressed RTF should be written to the stream pointed to by lpCompressedRTFStream
lpUncompressedRTFStream
[out] Pointer to the location where WrapCompressedRTFStream returns a stream for the uncompressed RTF.

Return Values

S_OK
The call succeeded and has returned the expected value or values.

Remarks

If the MAPI_MODIFY flag is passed in the ulFlags parameter, the lpCompressedRTFStream parameter must already be open for reading and writing. New, uncompressed RTF text should be written into the stream interface returned in lpUncompressedRTFStream. Because it is not possible to append the existing stream, the entire message text must be written.

If zero is passed in the ulFlags parameter, then lpCompressedRTFStream may be opened read-only. Only the entire message text can be read out of the stream interface returned in lpUncompressedRTFStream; it is not possible to search into the middle of the stream and begin reading.

WrapCompressedRTFStream assumes that the compressed stream's pointer is set to the beginning of the stream. Certain OLE IStream methods are not supported by the returned uncompressed stream. These include IStream::Clone, IStream::LockRegion, IStream::Revert, IStream::Seek, IStream::SetSize, IStream::Stat, and IStream::UnlockRegion. In order to copy to the entire stream, a read/write loop is needed.

Because the client writes new RTF in uncompressed format, it should use WrapCompressedRTFStream, rather than directly writing to the stream. RTF-aware clients should search for the STORE_UNCOMPRESSED_RTF flag in the PR_STORE_SUPPORT_MASK property and pass it to WrapCompressed RTFStream if it is set.

See Also

RTF Synchronization Functions, RTFSync


WrapStoreEntryID

The WrapStoreEntryID function converts a message store's internal entry identifier to an entry identifier more usable by the messaging system.

Quick Info

Header file: | MAPIUTIL.H
Implemented by: | MAPI
Called by: | Client applications and service providers

WrapStoreEntryID(
  ULONG ulFlags,
  LPTSTR szDLLName,
  ULONG cbOrigEntry,
  LPENTRYID lpOrigEntry,
  ULONG * lpcbWrappedEntry,
  LPENTRYID * lppWrappedEntry
);

Parameters

ulFlags
[in] Bitmask of flags. The following flag can be set:
MAPI_UNICODE
The strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
szDLLName
[in] The name of the message store provider DLL.
cbOrigEntry
[in] Size, in bytes, of the original entry identifier for the message store.
lpOrigEntry
[in] Pointer to an ENTRYID structure containing the original entry identifier.
lpcbWrappedEntry
[out] Pointer to the size, in bytes, of the new entry identifier.
lppWrappedEntry
[out] Pointer to a pointer to an ENTRYID structure containing the new entry identifier.

Remarks

A message store object retains an internal entry identifier which is meaningful only to service providers coresident with that message store. For other messaging components, MAPI supplies a wrapped version of the internal entry identifier that makes it recognizable as belonging to the message store. Coresident service providers should always be given the original unwrapped message store entry identifier; client applications should always be given the wrapped version, which is then usable anywhere in the messaging domain and in other domains.

A service provider can wrap a message store entry identifier using either the WrapStoreEntryID function or the IMAPISupport::WrapStoreEntryID method, which calls the WrapStoreEntryID function. The provider must wrap the entry identifier when exposing the message store's PR_ENTRYID property or writing it into a profile section, and when exposing the PR_STORE_ENTRYID property. MAPI wraps a message store entry identifier when responding to an IMAPISession::OpenMsgStore call.

When a client application passes a wrapped message store entry identifier to MAPI, for example in a IMAPISession::OpenEntry call, MAPI unwraps the entry identifier before using it to call a provider method such as IMSProvider::Logon or IMSProvider::CompareStoreIDs.

See Also

Entry Identifier Functions


XPProviderInit

The XPProviderInit function initializes a transport provider for operation.

Quick Info

Header file: | MAPISPI.H
Implemented by: | Transport providers
Called by: | MAPI

HRESULT XPProviderInit(
  HINSTANCE hInstance,
  LPMALLOC lpMalloc,
  LPALLOCATEBUFFER lpAllocateBuffer,
  LPALLOCATEMORE lpAllocateMore,
  LPFREEBUFFER lpFreeBuffer,
  ULONG ulFlags,
  ULONG ulMAPIVer,
  ULONG FAR * lpulProviderVer,
  LPXPPROVIDER FAR * lppXPProvider
);

Parameters

hInstance
[in] The instance of the transport provider's dynamic-link library (DLL) that MAPI used when it linked.
lpMalloc
[in] Pointer to a memory allocator object exposing the OLE IMalloc interface. The transport provider may need to use this allocation method when working with certain interfaces such as IStream.
lpAllocateBuffer
[in] Pointer to the MAPIAllocateBuffer function, to be used where required by MAPI to allocate memory.
lpAllocateMore
[in] Pointer to the MAPIAllocateMore function, to be used where required by MAPI to allocate additional memory.
lpFreeBuffer
[in] Pointer to the MAPIFreeBuffer function, to be used where required by MAPI to free memory.
ulFlags
[in] Bitmask of flags. The following flag can be set:
MAPI_NT_SERVICE
The provider is being loaded in the context of a Windows NT service, a special type of process without access to any user interface.
ulMAPIVer
[in] Version number of the service provider interface (SPI) that MAPI.DLL uses. For the current version number, see the MAPISPI.H header file.
lpulProviderVer
[out] Pointer to the version number of the SPI that this transport provider uses.
lppXPProvider
[out] Pointer to a pointer to the initialized transport provider object.

Return Values

S_OK
The call succeeded and has returned the expected value or values.
MAPI_E_VERSION
The SPI version being used by MAPI is not compatible with the SPI being used by this provider.

Remarks

MAPI calls the entry point function XPProviderInit to initialize a transport provider following a client logon. XPProviderInit is called once for each transport provider specified in the client's profile.

Notes to Implementers

A transport provider must implement XPProviderInit as an entry point function in the provider's DLL. The implementation must be based on the XPPROVIDERINIT function prototype, also specified in MAPISPI.H. MAPI defines XPPROVIDERINIT to use the standard MAPI initialization call type, STDMAPIINITCALLTYPE, which causes XPProviderInit to follow the CDECL calling convention. An advantage of CDECL is that calls can be attempted even if the number of calling parameters does not match the number of defined parameters.

A provider can be initialized multiple times as a result of appearing in several profiles in simultaneous use or of appearing more than once in the same profile. Because the provider object contains context, XPProviderInit must return a different provider object in lppXPProvider for each initialization, even for multiple initializations in the same process.

The transport provider should use the functions pointed to by lpAllocateBuffer, lpAllocateMore, and lpFreeBuffer for most memory allocation and deallocation. In particular, the provider must use these functions to allocate memory for use by client applications when calling object interfaces such as IMAPIProp::GetProps and IMAPITable::QueryRows. If the provider also expects to use the OLE memory allocator, it should call the IUnknown::AddRef method of the allocator object pointed to by the lpMalloc parameter.

For more information on writing XPProviderInit, see Initializing the Transport Provider. For more information on entry point functions, see Implementing a Service Provider Entry Point Function.

See Also

Provider Initialization Functions, ABProviderInit, HPProviderInit, IXPProvider : IUnknown, MSProviderInit


MAPI Properties

For a general explanation of how MAPI works with properties and a list of the properties available on each object, see Properties. For information on the property-related macros, see the SPropValue structure. For a comprehensive list of MAPI properties and their mappings to X.400 attributes, see Mapping of X.400 P2 Attributes to MAPI Properties.

Unlike members of OLE variant arrays, every member in a MAPI multivalued property array is of the same type.


PR_7BIT_DISPLAY_NAME

The PR_7BIT_DISPLAY_NAME property contains a 7-bit ASCII version of a messaging user's name.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x39FF
Property type: | PT_STRING8
Property tag: | 0x39FF001E

Remarks

The PR_7BIT_DISPLAY_NAME property can be considered a mapping of the PR_DISPLAY_NAME property into a 7-bit character set. Some messaging systems, such as Internet and certain X.400 links, are limited to the 128-character 7-bit ASCII code set. Gateways to such messaging systems can improve their performance by calling the IAddrBook::PrepareRecips method directly to retrieve the PR_7BIT_DISPLAY_NAME property to avoid extra processing for code conversion.

See Also

Supplemental Name Properties


PR_AB_DEFAULT_DIR

The PR_AB_DEFAULT_DIR property contains the entry identifier of the address book container that is to be shown to the user first.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3D06
Property type: | PT_BINARY
Property tag: | 0x3D060102

Remarks

Do not use this property. It is reserved for use by MAPI.

See Also

Reserved Properties


PR_AB_DEFAULT_PAB

The PR_AB_DEFAULT_PAB property contains the entry identifier of the address book container that is to be used as the personal address book.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3D07
Property type: | PT_BINARY
Property tag: | 0x3D070102

Remarks

Do not use this property. It is reserved for use by MAPI.

See Also

Reserved Properties


PR_AB_PROVIDER_ID

The PR_AB_PROVIDER_ID property contains an address book provider's MAPIUID structure.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Address book container objects
Must be a column in: | Hierarchy tables
Identifier: | 0x3615
Property type: | PT_BINARY
Property tag: | 0x36150102

Remarks

The MAPIUID structure identifies which address book provider supplies this particular container in the container hierarchy. The value is unique to each provider.

An address book provider can provide more than one identifier. For example, a provider that supplies two different containers can publish in PR_AB_PROVIDER_ID unique identifiers for each container.

PR_AB_PROVIDER_ID is analogous to the PR_MDB_PROVIDER property for message stores. Client applications can use PR_AB_PROVIDER_ID to find related rows in an address book hierarchy table.

See Also

Provider Properties


PR_AB_PROVIDERS

The PR_AB_PROVIDERS property contains a list of identifiers for address book providers in the current profile.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3D01
Property type: | PT_BINARY
Property tag: | 0x3D010102

Remarks

Do not use this property. It is reserved for use by MAPI.

See Also

Reserved Properties


PR_AB_SEARCH_PATH

The PR_AB_SEARCH_PATH property contains a list of entry identifiers for address book containers that are to be searched to resolve names.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3D05
Property type: | PT_MV_BINARY
Property tag: | 0x3D051102

Remarks

Do not use this property. It is reserved for use by MAPI.

See Also

Reserved Properties


PR_AB_SEARCH_PATH_UPDATE

The PR_AB_SEARCH_PATH_UPDATE property contains a list of entry identifiers for address book containers explicitly configured by the user.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3D11
Property type: | PT_BINARY
Property tag: | 0x3D110102

Remarks

Do not use this property. It is reserved for use by MAPI.

See Also

Reserved Properties


PR_ACCESS

The PR_ACCESS property contains a bitmask of flags indicating the operations a client application can perform on the open object.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Folder and message objects
Identifier: | 0x0FF4
Property type: | PT_LONG
Property tag: | 0x0FF40003

Remarks

Zero or more of the following flags can be set for the PR_ACCESS property:

MAPI_ACCESS_CREATE_ASSOCIATED
The client can create an associated contents table.
MAPI_ACCESS_CREATE_CONTENTS
The client can create a contents table.
MAPI_ACCESS_CREATE_HIERARCHY
The client can create a hierarchy table.
MAPI_ACCESS_DELETE
The client can delete the object.
MAPI_ACCESS_MODIFY
The client can write to the object.
MAPI_ACCESS_READ
The client can read the object.

The MAPI_ACCESS_DELETE, MAPI_ACCESS_MODIFY, and MAPI_ACCESS_READ flags are found on folder and message objects and in the PR_ACCESS column in contents tables and associated contents tables. The MAPI_ACCESS_CREATE_ASSOCIATED, MAPI_ACCESS_CREATE_CONTENTS, and MAPI_ACCESS_CREATE_HIERARCHY flags are found on folder objects only.

See Also

General Object Properties, PR_ACCESS_LEVEL


PR_ACCESS_LEVEL

The PR_ACCESS_LEVEL property contains a bitmask of flags indicating the level at which a client application can access the open object.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Address book container, distribution list, folder, messaging user, message, and message store objects
Identifier: | 0x0FF7
Property type: | PT_LONG
Property tag: | 0x0FF70003

Remarks

The PR_ACCESS_LEVEL property is used to determine whether or not read/write access was granted. Calls to the IMsgStore::OpenEntry method can request read/write access. By default, access is read-only, although the access granted is defined by the service provider. A provider can grant read/write access when the client requested read-only access.

The following flag can be set:

MAPI_MODIFY
Read/write access was granted.

See Also

General Object Properties, PR_ACCESS


PR_ACCOUNT

The PR_ACCOUNT property contains the recipient's account name.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A00
Property type: | PT_TSTRING
Property tag: | 0x3A00001E (0x3A00001F for Unicode)

Remarks

The PR_ACCOUNT property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information about this group of properties, see IMailUser::IMAPIProp.

PR_ACCOUNT commonly contains the recipient's e-mail name, that is, the final component of the e-mail address, which uniquely identifies the recipient within the local organization. The e-mail name corresponds to the X.400 distinguished name, which is meant to be a short name guaranteed to be unique within a certain messaging domain.

See Also

Personal Information Properties


PR_ACKNOWLEDGEMENT_MODE

The PR_ACKNOWLEDGEMENT_MODE property contains the identifier of the mode for message acknowledgment.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0001
Property type: | PT_LONG
Property tag: | 0x00010003
Corresponding X.400 attribute: | IM_ACKNOWLEDGEMENT_MODE

Remarks

The PR_ACKNOWLEDGEMENT_MODE property can have exactly one of the following values:

0
Manual acknowledgment.
1
Automatic acknowledgment.

See Also

Message Properties, PR_MESSAGE_CLASS


PR_ADDRTYPE

The PR_ADDRTYPE property contains the messaging user's e-mail address type, such as SMTP.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Distribution list and messaging user objects
Identifier: | 0x3002
Property type: | PT_TSTRING
Property tag: | 0x3002001E (0x3002001F for Unicode)

Remarks

The PR_ADDRTYPE property is one of the base address properties common to all messaging users. It specifies which messaging system MAPI uses to handle a given message.

PR_ADDRTYPE also determines the format of the address string in the PR_EMAIL_ADDRESS property. The string provided by PR_ADDRTYPE can contain only the uppercase alphabetic characters from A through Z and the numbers from 0 through 9.

Valid PR_ADDRTYPE examples include:

FAX
MHS
PROFS
SMTP
X400

For more information on the base address properties, see Base Address Properties. For more information on address types, see Address Types.

See Also

Base Address Properties


PR_ALTERNATE_RECIPIENT

The PR_ALTERNATE_RECIPIENT property contains a list of entry identifiers for alternate recipients designated by the originally intended recipient.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects.
Identifier: | 0x3A01
Property type: | PT_BINARY
Property tag: | 0x3A010102
Corresponding X.400 attribute: | MH_T_ALTERNATE_RECIPIENT_NAME

Remarks

The PR_ALTERNATE_RECIPIENT property is used in autoforwarded messages. It contains a FLATENTRYLIST structure of alternate recipients. If autoforwarding is not permitted or if no alternate recipient has been designated, a nondelivery report should be generated.

See Also

Alternate Recipient Properties


PR_ALTERNATE_RECIPIENT_ALLOWED

The PR_ALTERNATE_RECIPIENT_ALLOWED property contains TRUE if the sender permits autoforwarding of this message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0002
Property type: | PT_BOOLEAN
Property tag: | 0x0002000B
Corresponding X.400 attribute: | MH_T_ALTERNATE_RECIPIENT_ALLOWED

Remarks

If autoforwarding is not permitted or if no alternate recipient has been designated, a nondelivery report should be generated.

See Also

Alternate Recipient Properties


PR_ANR

The PR_ANR property contains a string value for use in a property restriction on an address book container contents table.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x360C
Property type: | PT_TSTRING
Property tag: | 0x360C001E (0x360C001F for Unicode)

Remarks

The PR_ANR property does not belong to any object; it is furnished by address book providers in SPropertyRestriction structures. This property contains an ambiguous name resolution (ANR) string that can be tested against an address book container's contents table to find corresponding message recipients.

Address book providers match the value of PR_ANR against every entry in the contents table, using a provider-defined matching algorithm. The column or columns used in this match are chosen by the provider as part of the algorithm. The PR_DISPLAY_NAME column is the most commonly used; the PR_ACCOUNT column is also useful when it contains the user's e-mail name.

For more information on ambiguous name resolution, see Address Book Restrictions.

See Also

Specialized Usage Properties, IAddrBook::ResolveName, IABContainer::ResolveNames


PR_ASSISTANT

The PR_ASSISTANT property contains the name of the recipient's administrative assistant.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A30
Property type: | PT_TSTRING
Property tag: | 0x3A30001E (0x3A30001F for Unicode)

Remarks

The PR_ASSISTANT property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties, PR_ASSISTANT_TELEPHONE_NUMBER


PR_ASSISTANT_TELEPHONE_NUMBER

The PR_ASSISTANT_TELEPHONE_NUMBER property contains the telephone number of the recipient's administrative assistant.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A2E
Property type: | PT_TSTRING
Property tag: | 0x3A2E001E (0x3A2E001F for Unicode)

Remarks

The PR_ASSISTANT_TELEPHONE_NUMBER property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

The telephone number is for the assistant specified in the PR_ASSISTANT property.

See Also

Personal Information Properties


PR_ASSOC_CONTENT_COUNT

The PR_ASSOC_CONTENT_COUNT property contains the count of items in the associated contents table of the folder.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Folder objects
Identifier: | 0x3617
Property type: | PT_LONG
Property tag: | 0x36170003

Remarks

The PR_FOLDER_ASSOCIATED_CONTENTS property contains the associated contents table of the folder.

See Also

Folder Properties, PR_ACCESS


PR_ATTACH_ADDITIONAL_INFO

The PR_ATTACH_ADDITIONAL_INFO property provides file type information for a non-Windows attachment.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x370F
Property type: | PT_BINARY
Property tag: | 0x370F0102

Remarks

The PR_ATTACH_ADDITIONAL_INFO property is used to provide metadata about a particular attachment based on the attachment's encoding. For example, when the PR_ATTACH_ENCODING property contains MacBinary, PR_ATTACH_ADDITIONAL_INFO contains a string which represents the Macintosh file creator and file type, formatted as ":CREA:TYPE" for the encoded Macintosh file.

See Also

Attachment Properties


PR_ATTACH_CONTENT_BASE

The PR_ATTACH_CONTENT_BASE property contains the content base header of a MIME message attachment.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x3711
Property type: | PT_TSTRING
Property tag: | 0x3711001E (0x3711001F for Unicode)

Remarks

The PR_ATTACH_CONTENT_BASE property is used for MHTML support. It represents the content base header for the appropriate MIME body part.

See Also

Attachment Properties


PR_ATTACH_CONTENT_ID

The PR_ATTACH_CONTENT_ID property contains the content identification header of a MIME message attachment.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x3712
Property type: | PT_TSTRING
Property tag: | 0x3712001E (0x3712001F for Unicode)

Remarks

The PR_ATTACH_CONTENT_ID property is used for MHTML support. It represents the content identification header for the appropriate MIME body part.

See Also

Attachment Properties


PR_ATTACH_CONTENT_LOCATION

The PR_ATTACH_CONTENT_LOCATION property contains the content location header of a MIME message attachment.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x3713
Property type: | PT_TSTRING
Property tag: | 0x3713001E (0x3713001F for Unicode)

Remarks

The PR_ATTACH_CONTENT_LOCATION property is used for MHTML support. It represents the content location header for the appropriate MIME body part.

See Also

Attachment Properties


PR_ATTACH_DATA_BIN

The PR_ATTACH_DATA_BIN property contains binary attachment data typically accessed through the OLE IStream interface.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x3701
Property type: | PT_BINARY
Property tag: | 0x37010102
Corresponding X.400 attribute: | IM_EXTERNAL_DATA or IM_BILATERAL_DATA

Remarks

The PR_ATTACH_DATA_BIN property holds the attachment when the value of the PR_ATTACH_METHOD property is ATTACH_BY_VALUE, which is the usual attachment method and the only one required to be supported. PR_ATTACH_DATA_BIN also holds an OLE 1.0 OLESTREAM attachment when the value of PR_ATTACH_METHOD is ATTACH_OLE.

OLESTREAM attachments can be copied into a file by calling the OLE IStream::CopyTo method. The OLE encoding type can be determined from the PR_ATTACH_TAG property.

For an OLE document file attachment, the message store provider must respond to an IMAPIProp::OpenProperty call on PR_ATTACH_DATA_OBJ and may optionally respond to a call on PR_ATTACH_DATA_BIN. Note that PR_ATTACH_DATA_BIN and PR_ATTACH_DATA_OBJ share the same property identifier and thus are two renditions of the same property.

For a storage object, such as a compound file in OLE 2.0 docfile format, some service providers allow it to be opened with the MAPI IStreamDocfile interface for improved performance. A provider supporting IStreamDocfile must expose it on PR_ATTACH_DATA_OBJ and may optionally expose it on PR_ATTACH_DATA_BIN.

For more information on OLE interfaces and formats, see the OLE Programmer's Reference.

See Also

Attachment Properties


PR_ATTACH_DATA_OBJ

The PR_ATTACH_DATA_OBJ property contains an attachment object typically accessed through the OLE IStorage interface.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x3701
Property type: | PT_OBJECT
Property tag: | 0x3701000D
Corresponding X.400 attribute | IM_EXTERNAL_DATA

Remarks

The PR_ATTACH_DATA_OBJ property holds the attachment when the value of the PR_ATTACH_METHOD property is ATTACH_EMBEDDED_MSG or ATTACH_OLE. The OLE encoding type can be determined from PR_ATTACH_TAG.

For an attachment associated with the ATTACH_EMBEDDED_MSG value, the IMessage:IMAPIProp inferface can be used for faster access.

For an embedded dynamic OLE object, the PR_ATTACH_DATA_OBJ property contains its own rendering information, and the PR_ATTACH_RENDERING property should be either nonexistent or empty.

For an OLE document file attachment, the message store provider must respond to an IMAPIProp::OpenProperty call on PR_ATTACH_DATA_OBJ and may optionally respond to a call on PR_ATTACH_DATA_BIN. The PR_ATTACH_DATA_BIN and PR_ATTACH_DATA_OBJ properties share the same property identifier and thus are two renditions of the same property.

For a storage object, such as a compound file in OLE 2.0 docfile format, some service providers allow it to be opened with the MAPI IStreamDocfile interface, a subclass of IStream with no additional members, designed to optimize performance. The potential saving is enough to justify attempting to open PR_ATTACH_DATA_OBJ through IStreamDocfile. If MAPI_E_INTERFACE_NOT_SUPPORTED is returned, the client can then open PR_ATTACH_DATA_BIN with IStream.

If the client application or service provider cannot open an attachment subobject using PR_ATTACH_DATA_OBJ with the help of PR_ATTACH_METHOD, it should use PR_ATTACH_DATA_BIN.

For more information on OLE interfaces and formats, see the OLE Programmer's Reference.

See Also

Attachment Properties


PR_ATTACH_ENCODING

The PR_ATTACH_ENCODING property contains an ASN.1 object identifier specifying the encoding for an attachment.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x3702
Property type: | PT_BINARY
Property tag: | 0x37020102

Remarks

The PR_ATTACH_ENCODING property identifies the algorithm used to transform the data in an attachment.

Note The PR_ATTACH_ENCODING and PR_ATTACH_TAG properties should not be confused. They are not paired or related. PR_ATTACH_TAG identifies the application that originally generated the attachment. "Object" has a much more general meaning in the term object identifier, and in X.400, than in object-oriented programming.

The object identifier syntax and sample object identifiers are defined in the MAPIOID.H header file. Values for PR_ATTACH_ENCODING are not limited to those defined in MAPIOID.H. For example, attached Macintosh files can use an identifier such as MacBinary.

For complete information on these object identifiers, see the documentation on ASN.1, X.208, and X.209. The object identifier is found in the application-reference element of the FTBP (File Transfer Body Part) environment.

See Also

Attachment Properties


PR_ATTACH_EXTENSION

The PR_ATTACH_EXTENSION property contains a filename extension that indicates the document type of an attachment.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x3703
Property type: | PT_TSTRING
Property tag: | 0x3703001E (0x3703001F for Unicode)

Remarks

The PR_ATTACH_EXTENSION property is set by the client application at submission time.

The messaging system uses PR_ATTACH_EXTENSION when converting message attachments (in-route conversion) or launching applications based on attachments in received messages. If the sending client does not provide a value for this property, the message store handling the attachment is not obligated to generate it. The receiving client should first check for PR_ATTACH_EXTENSION, and if it is not provided, should parse the filename extension from the attachment's PR_ATTACH_FILENAME or PR_ATTACH_LONG_FILENAME property.

See Also

Attachment Properties


PR_ATTACH_FILENAME

The PR_ATTACH_FILENAME property contains an attachment's base filename and extension, excluding path.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x3704
Property type: | PT_TSTRING
Property tag: | 0x3704001E (0x3704001F for Unicode)
Corresponding X.400 attribute: | IM_EXTERNAL_PARAMETERS

Remarks

It is recommended that messaging user objects expose the PR_ATTACH_FILENAME property. PR_ATTACH_FILENAME pertains to the ATTACH_BY_VALUE, ATTACH_BY_REFERENCE, ATTACH_BY_REF_RESOLVE, and ATTACH_BY_REF_ONLY values of the PR_ATTACH_METHOD property. PR_ATTACH_FILENAME is required when any of these values is used.

PR_ATTACH_FILENAME can be used as a suggested filename for saving the attachment and to supply the filename extension if the PR_ATTACH_EXTENSION property is not provided.

The filename is restricted to eight characters plus a three-character extension. For a platform that supports long filenames, set both this property and the PR_ATTACH_LONG_FILENAME property.

MAPI works only with filenames, and other strings passed to it, in the ANSI character set. Client applications that use filenames in an OEM character set must convert them to ANSI before calling MAPI.

See Also

Attachment Properties


PR_ATTACH_FLAGS

The PR_ATTACH_FLAGS property contains a bitmask of flags for an attachment.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x3714
Property type: | PT_LONG
Property tag: | 0x37140003

Remarks

The PR_ATTACH_FLAGS property is used for MHTML support.

One or more of the following flags can be set for the PR_ATTACH_FLAGS bitmask:

ATT_INVISIBLE_IN_HTML
Indicates that this attachment is not available to Hypertext Markup Language (HTML) rendering applications and should be ignored in MIME processing.
ATT_INVISIBLE_IN_RTF
Indicates that this attachment is not available to applications rendering in Rich Text Format (RTF) and should be ignored by MAPI.

If the PR_ATTACH_FLAGS property is zero or absent, the attachment is to be processed by all applications.

See Also

Attachment Properties


PR_ATTACH_LONG_FILENAME

The PR_ATTACH_LONG_FILENAME property contains an attachment's long filename and extension, excluding path.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x3707
Property type: | PT_TSTRING
Property tag: | 0x3707001E (0x3707001F for Unicode)

Remarks

The PR_ATTACH_LONG_FILENAME property pertains to the ATTACH_BY_VALUE, ATTACH_BY_REFERENCE, ATTACH_BY_REF_RESOLVE, and ATTACH_BY_REF_ONLY values of the PR_ATTACH_METHOD property. Platforms that support long filenames should set both the PR_ATTACH_LONG_FILENAME and PR_ATTACH_FILENAME properties when sending, and should check PR_ATTACH_LONG_FILENAME first when receiving.

The client application should set this property to a suggested long filename to be used if the host computer receiving a message supports long filenames. PR_ATTACH_LONG_FILENAME can be used as a filename for saving the attachment, and to supply the filename extension if the PR_ATTACH_EXTENSION property is not provided.

Unlike the filename provided by PR_ATTACH_FILENAME, this name is not restricted to an eight-character filename plus a three-character extension. Instead, it can be up to 256 characters long, including the filename, extension, and separator period.

MAPI works only with filenames, and other strings passed to it, in the ANSI character set. Client applications that use filenames in an OEM character set must convert them to ANSI before calling MAPI.

See Also

Attachment Properties


PR_ATTACH_LONG_PATHNAME

The PR_ATTACH_LONG_PATHNAME property contains an attachment's fully qualified long path and filename.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x370D
Property type: | PT_TSTRING
Property tag: | 0x370D001E (0x370D001F for Unicode)

Remarks

The PR_ATTACH_LONG_PATHNAME property is applicable when you use any of the PR_ATTACH_METHOD property's values that indicate attachment by reference: ATTACH_BY_REFERENCE, ATTACH_BY_REF_RESOLVE, or ATTACH_BY_REF_ONLY. Platforms that support long filenames should set both the PR_ATTACH_LONG_PATHNAME and PR_ATTACH_PATHNAME properties when sending, and should check PR_ATTACH_LONG_PATHNAME first when receiving.

The client application should set this property to a suggested long path and filename to be used if the host machine receiving a message supports long filenames. Setting PR_ATTACH_LONG_PATHNAME indicates that the attachment data is not included with the message but is available on a common file server.

Unlike the directories and filenames provided by PR_ATTACH_PATHNAME, these directories and filenames are not restricted to an eight-character directory or filename plus three-character extension. Instead, each directory or filename can be up to 256 characters long, including the name, extension, and separator period. However, the overall path is limited to 256 characters.

Clients should use a universal naming convention (UNC) in most cases when the file is shared, and should use an absolute path when the file is local and in some shared cases, such as with NetWare®.

MAPI works only with paths, filenames, and other strings passed to it in the ANSI character set. Client applications that use paths and filenames in an OEM character set must convert them to ANSI before calling MAPI.

See Also

Attachment Properties


PR_ATTACH_METHOD

The PR_ATTACH_METHOD property contains a MAPI-defined constant representing the way the contents of an attachment can be accessed.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Attachment subobjects
Identifier: | 0x3705
Property type: | PT_LONG
Property tag: | 0x37050003

Remarks

The PR_ATTACH_METHOD property can have exactly one of the following values:

NO_ATTACHMENT
The attachment has just been created.
ATTACH_BY_VALUE
The PR_ATTACH_DATA_BIN property contains the attachment data.
ATTACH_BY_REFERENCE
The PR_ATTACH_PATHNAME or PR_ATTACH_LONG_PATHNAME property contains a fully qualified path identifying the attachment to recipients with access to a common file server.
ATTACH_BY_REF_RESOLVE
The PR_ATTACH_PATHNAME or PR_ATTACH_LONG_PATHNAME property contains a fully qualified path identifying the attachment.
ATTACH_BY_REF_ONLY
The PR_ATTACH_PATHNAME or PR_ATTACH_LONG_PATHNAME property contains a fully qualified path identifying the attachment.
ATTACH_EMBEDDED_MSG
The PR_ATTACH_DATA_OBJ property contains an embedded object that supports the IMessage interface.
ATTACH_OLE
The attachment is an embedded OLE object.

When created, all attachment objects have an initial PR_ATTACH_METHOD value of NO_ATTACHMENT.

Client applications and service providers are only required to support the attachment method represented by the ATTACH_BY_VALUE value. The other attachment methods are optional. The message store does not enforce any consistency between the value of PR_ATTACH_METHOD and the values of the other attachment properties.

Universal naming convention (UNC) names are recommended for fully qualified paths, which should be used with ATTACH_BY_REFERENCE and ATTACH_BY_REF_ONLY. With ATTACH_BY_REF_RESOLVE, an absolute path is faster, because the MAPI spooler converts the attachment to ATTACH_BY_VALUE.

If ATTACH_BY_REFERENCE is set, PR_ATTACH_DATA_BIN must be empty. An outbound gateway can turn an ATTACH_BY_REFERENCE attachment into an ATTACH_BY_VALUE attachment by copying the attachment data into the PR_ATTACH_DATA_BIN property.

If ATTACH_BY_REF_RESOLVE is set, PR_ATTACH_DATA_BIN must be empty. When the message that contains the ATTACH_BY_REF_RESOLVE attachment is sent, the MAPI spooler copies the attachment data into an ATTACH_BY_VALUE attachment. This resolution process places the attachment data in PR_ATTACH_DATA_BIN.

If ATTACH_BY_REF_ONLY is set, PR_ATTACH_DATA_BIN must be empty, and the messaging system never resolves the attachment reference. Use this value when you want to send the link but not the data.

When the OLE object is in OLE 2.0 IStorage format, the data are accessible through PR_ATTACH_DATA_OBJ. When the OLE object is in OLE 1.0 OLESTREAM format, the data are accessible through PR_ATTACH_DATA_BIN as an IStream. The type of the OLE encoding can be determined by the PR_ATTACH_TAG value.

For more information on OLE interfaces and formats, see the OLE Programmer's Reference.

See Also

Attachment Properties, PR_STORE_SUPPORT_MASK


PR_ATTACH_MIME_SEQUENCE

The PR_MIME_SEQUENCE property contains the MIME sequence number of a MIME message attachment.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x3710
Property type: | PT_LONG
Property tag: | 0x37100003

Remarks

The PR_MIME_SEQUENCE property is used for MHTML support. It represents the sequence number of the attachment within the parent MIME multipart body part of the MIME message.

See Also

Attachment Properties


PR_ATTACH_MIME_TAG

The PR_ATTACH_MIME_TAG property contains formatting information about a Multipurpose Internet Mail Extensions (MIME) attachment.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x370E
Property type: | PT_TSTRING
Property tag: | 0x370E001E (0x370E001F for Unicode)

Remarks

If the PR_ATTACH_TAG property contains the value OID_MIMETAG, the transport provider should look at the PR_ATTACH_MIME_TAG property to determine how the attachment is formatted.

PR_ATTACH_MIME_TAG is copied from the Content-type parameter of the inbound MIME header. The composition of the string is defined in the RFC 1521 document. The format is type/subtype, such as application/binary or text/plain.

See Also

Attachment Properties


PR_ATTACH_NUM

The PR_ATTACH_NUM property contains a number that uniquely identifies the attachment within its parent message.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Attachment subobjects
Identifier: | 0x0E21
Property type: | PT_LONG
Property tag: | 0x0E210003

Remarks

Message stores generate and maintain the PR_ATTACH_NUM property. The attachment number is the secondary sort key, after the rendering position, in the attachment table.

PR_ATTACH_NUM is used to open the attachment with the IMessage::OpenAttach method. Within a client application's session, the PR_ATTACH_NUM property of a message attachment remains constant as long as the attachment table is open.

The message store propagates changes to the table using the IMessage::CreateAttach and IMessage::DeleteAttach methods. At its option the message store can generate table notifications on open attachment tables so that clients can resynchronize to those changes.

See Also

Attachment Properties


PR_ATTACH_PATHNAME

The PR_ATTACH_PATHNAME property contains an attachment's fully qualified path and filename.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x3708
Property type: | PT_TSTRING
Property tag: | 0x3708001E (0x3708001F for Unicode)

Remarks

It is recommended that attachment subobjects expose the PR_ATTACH_PATHNAME property. Setting PR_ATTACH_PATHNAME indicates that the attachment data is not included with the message but is available on a common file server. PR_ATTACH_PATHNAME is required in conjunction with any of the PR_ATTACH_METHOD flags that indicate attachment by reference: ATTACH_BY_REFERENCE, ATTACH_BY_REF_RESOLVE, or ATTACH_BY_REF_ONLY.

Each directory or filename is restricted to an eight-character name plus a three-character extension. The overall path is restricted to 256 characters. For a platform that supports long filenames, set both the PR_ATTACH_PATHNAME and PR_ATTACH_LONG_PATHNAME properties.

Client applications should use a universal naming convention (UNC) in most cases when the file is shared, and should use an absolute path when the file is local and in some shared cases, such as with NetWare.

MAPI works only with paths, filenames, and other strings passed to it in the ANSI character set. Clients that use paths and filenames in an OEM character set must convert them to ANSI before calling MAPI.

See Also

Attachment Properties, ScLocalPathFromUNC, ScUNCFromLocalPath


PR_ATTACH_RENDERING

The PR_ATTACH_RENDERING property contains a Microsoft Windows metafile with rendering information for an attachment.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x3709
Property type: | PT_BINARY
Property tag: | 0x37090102

Remarks

The purpose of the PR_ATTACH_RENDERING property is to provide an icon or other pictorial representation that can be displayed within the parent message at the point of attachment. Such representation typically includes the name of the attachment, if any, and the nature of the attachment, such as a Microsoft Word document. A client application can use this representation in the display of the message.

For an attached file, PR_ATTACH_RENDERING usually portrays an icon for the file.

For an attached message, PR_ATTACH_RENDERING is typically not set. A client application needing to render an attached message should obtain its PR_MESSAGE_CLASS property, call IMAPIFormMgr::ResolveMessageClass for a pointer to the corresponding form information object, open the IMAPIFormInfo interface on that object, and use GetProps to retrieve the PR_ICON or PR_MINI_ICON property.

For an embedded static OLE object, PR_ATTACH_RENDERING contains a Microsoft Windows metafile that can be used to draw the attachment representation in a window.

For an embedded dynamic OLE object, the client should use the OLE data to generate the rendering information.

In all cases, the client application should be aware that PR_ATTACH_RENDERING is usually several hundred bytes in size and is subject to truncation in the attachment table. If a client wishes to render the attachment from PR_ATTACH_RENDERING without opening the attachment itself, it must work within the table truncation rule. For more information, see Working with Large Columns.

See Also

Attachment Properties


PR_ATTACH_SIZE

The PR_ATTACH_SIZE property contains the sum, in bytes, of the sizes of all properties on an attachment.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attacment subobjects
Identifier: | 0x0E20
Property type: | PT_LONG
Property tag: | 0x0E200003

Remarks

It is recommended that attachment subobjects expose the PR_ATTACH_SIZE property. The sum contained in PR_ATTACH_SIZE includes the size of the PR_ATTACH_DATA_BIN or PR_ATTACH_DATA_OBJ property. Accordingly, PR_ATTACH_SIZE is usually larger than the contents of the attachment alone.

This property can be used to check the approximate size of the attachment before performing a remote transfer by modem and to display progress indicators when saving the attachment to disk. It is particularly useful with attached OLE objects.

See Also

Attachment Properties, PR_MESSAGE_SIZE


PR_ATTACH_TAG

The PR_ATTACH_TAG property contains an ASN.1 object identifier specifying the application that supplied an attachment.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x370A
Property type: | PT_BINARY
Property tag: | 0x370A0102
Corresponding X.400 attribute: | IM_EXTERNAL_PARAMETERS

Remarks

The PR_ATTACH_TAG property identifies the application that originally generated the attachment.

Note The PR_ATTACH_ENCODING and PR_ATTACH_TAG properties should not be confused. They are not paired or related. PR_ATTACH_ENCODING identifies the algorithm used to transform the data in an attachment. "Object" has a much more general meaning in the term object identifier, and in X.400 usage, than in object-oriented programming.

The object identifier syntax and sample object identifiers are defined in the MAPIOID.H header file. Values for PR_ATTACH_TAG are not limited to those defined in MAPIOID.H.

For complete information on these object identifiers, see the documentation on ASN.1, X.208, and X.209. The object identifier is found in the application-reference element of the File Transfer Body Part (FTBP) environment.

See Also

Attachment Properties, PR_ATTACH_MIME_TAG


PR_ATTACH_TRANSPORT_NAME

The PR_ATTACH_TRANSPORT_NAME property contains the name of an attachment file modified so that it can be correlated with TNEF messages.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x370C
Property type: | PT_TSTRING
Property tag: | 0x370C001E (0x370C001F for Unicode)

Remarks

TNEF and the transport provider use the PR_ATTACH_TRANSPORT_NAME property. It is usually not available to client applications.

This property is commonly used by TNEF when the underlying messaging system doesn't support the supplied filenames. For example, PR_ATTACH_TRANSPORT_NAME is used when the user attaches multiple files with the same name, such as five files named CONFIG.SYS. The transport provider must modify the names to ensure uniqueness. Each modified name appears in its attachment's PR_ATTACH_TRANSPORT_NAME property.

MAPI works only with filenames, and other strings passed to it, in the ANSI character set. Applications that use filenames in an OEM character set must convert them to ANSI before calling MAPI.

See Also

Attachment Properties


PR_ATTACHMENT_X400_PARAMETERS

The PR_ATTACHMENT_X400_PARAMETERS property was originally meant to contain an ASN.1 object identifier specifying how the attachment should be handled during transmission.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3700
Property type: | PT_BINARY
Property tag: | 0x37000102
Corresponding X.400 attribute: | IM_EXTERNAL_PARAMETERS

Remarks

Do not use this property. It is not supported in MAPI 1.0.

See Also

Unused Properties


PR_AUTHORIZING_USERS

The PR_AUTHORIZING_USERS property contains a list of entry identifiers for users who have authorized the sending of a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0003
Property type: | PT_BINARY
Property tag: | 0x00030102
Corresponding X.400 attribute: | IM_AUTHORIZING_USERS

Remarks

The message store does not maintain the PR_AUTHORIZING_USERS property.

See Also

Message Properties, PR_ENTRYID


PR_AUTO_FORWARD_COMMENT

The PR_AUTO_FORWARD_COMMENT property contains a comment added by the autoforwarding agent.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0004
Property type: | PT_TSTRING
Property tag: | 0x0004001E (0x0004001F for Unicode)
Corresponding X.400 attribute: | IM_AUTO_FORWARD_COMMENT

See Also

Autoforwarding Properties


PR_AUTO_FORWARDED

The PR_AUTO_FORWARDED property contains TRUE if an automatic agent has forwarded a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0005
Property type: | PT_BOOLEAN
Property tag: | 0x0005000B
Corresponding X.400 attribute: | IM_AUTO_FORWARDED

See Also

Autoforwarding Properties


PR_BODY

The PR_BODY property contains the message text.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x1000
Property type: | PT_TSTRING
Property tag: | 0x1000001E (0x1000001F for Unicode)
Corresponding X.400 attribute: | IM_BODY and IM_TEXT

Remarks

The PR_BODY property is typically used only in an interpersonal message (IPM).

Message stores that support Rich Text Format (RTF) ignore any changes to white space in the message text. When PR_BODY is stored for the first time, the message store also generates and stores the PR_RTF_COMPRESSED property, the RTF version of the message text. If the IMAPIProp::SaveChanges method is subsequently called and PR_BODY has been modified, the message store calls the RTFSync function to ensure synchronization with the RTF version. If only white space has been changed, the properties are left unchanged. This preserves any nontrivial RTF formatting when the message travels through non-RTF-aware clients and messaging systems.

The value for PR_BODY must be expressed in the code page of the operating system that MAPI is running on.

See Also

Message Text Properties, PR_RTF_IN_SYNC


PR_BODY_CRC

The PR_BODY_CRC property contains a circular redundancy check (CRC) value on the message text.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0E1C
Property type: | PT_LONG
Property tag: | 0x0E1C0003

Remarks

The message store can use any CRC algorithm that generates a PT_LONG value. It must compute PR_BODY_CRC as part of the IMAPIProp::SaveChanges method when the PR_BODY property has been set for the first time and whenever it has been subsequently modified.

A client application uses PR_BODY_CRC to aid in comparing message text strings contained in PR_BODY properties or their variants. Using this property, the client can quickly and easily detect when the message text has changed. It can realize significant performance gains by using PR_BODY_CRC instead of obtaining PR_BODY from the message store and comparing it with a local version.

See Also

Message Text Properties


PR_BODY_HTML

The PR_BODY_HTML property contains the Hypertext Markup Language version of the message text.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x1013
Property type: | PT_TSTRING
Property tag: | 0x1013001E (0x1013001F for Unicode)

Remarks

The PR_BODY_HTML property contains the same message text as the PR_BODY property but in Hypertext Markup Language (HTML).

A message store that supports HTML indicates this by setting the STORE_HTML_OK flag in its PR_STORE_SUPPORT_MASK property.

See Also

Message Text Properties


PR_BUSINESS_FAX_NUMBER

The PR_BUSINESS_FAX_NUMBER property contains the telephone number of the recipient's business fax machine.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A24
Property type: | PT_TSTRING
Property tag: | 0x3A24001E (0x3A24001F for Unicode)

Remarks

The PR_BUSINESS_FAX_NUMBER property is one of the properties that provide identification and access information about a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_BUSINESS_TELEPHONE_NUMBER

The PR_BUSINESS_TELEPHONE_NUMBER property contains the primary telephone number of the recipient's place of business.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A08
Property type: | PT_TSTRING
Property tag: | 0x3A08001E (0x3A08001F for Unicode)

Remarks

The PR_BUSINESS_TELEPHONE_NUMBER property is one of the properties that provide identification and access information about a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

MAPI also supports the PR_OFFICE_TELEPHONE_NUMBER property, which is synonymous with PR_BUSINESS_TELEPHONE_NUMBER.

See Also

Personal Information Properties


PR_BUSINESS2_TELEPHONE_NUMBER

The PR_BUSINESS2_TELEPHONE_NUMBER property contains a secondary telephone number at the recipient's place of business.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A1B
Property type: | PT_TSTRING
Property tag: | 3A1B001E (3A1B001F for Unicode)

Remarks

The PR_BUSINESS2_TELEPHONE_NUMBER property is one of the properties that provide identification and access information about a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

MAPI also supports the PR_OFFICE2_TELEPHONE_NUMBER property, which is synonymous with PR_BUSINESS2_TELEPHONE_NUMBER.

See Also

Personal Information Properties, PR_BUSINESS_TELEPHONE_NUMBER


PR_CALLBACK_TELEPHONE_NUMBER

The PR_CALLBACK_TELEPHONE_NUMBER property contains a telephone number that the message recipient can use to reach the sender.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A02
Property type: | PT_TSTRING
Property tag: | 0x3A02001E (0x3A02001F for Unicode)

Remarks

The PR_CALLBACK_TELEPHONE_NUMBER property is one of the properties that provide identification and access information about a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_CAPABILITIES_TABLE

The PR_CAPABILITIES_TABLE property was originally meant to contain an embedded table object to provide a summary of the address book capabilities.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3903
Property type: | PT_OBJECT
Property tag: | 0x3903000D

Remarks

Do not use this property. It is not supported in MAPI 1.0.

See Also

Unused Properties


PR_CAR_TELEPHONE_NUMBER

The PR_CAR_TELEPHONE_NUMBER property contains the recipient's car telephone number.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A1E
Property type: | PT_TSTRING
Property tag: | 0x3A1E001E (0x3A1E001F for Unicode)

Remarks

The PR_CAR_TELEPHONE_NUMBER property is one of the properties that provide identification and access information about a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_CLIENT_SUBMIT_TIME

The PR_CLIENT_SUBMIT_TIME property contains the date and time the message sender submitted a message.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0039
Property type: | PT_SYSTIME
Property tag: | 0x00390040
Corresponding X.400 attribute: | MH_T_SUBMISSION_TIME

Remarks

The store provider sets PR_CLIENT_SUBMIT_TIME to the time the client application calls IMessage::SubmitMessage.

See Also

Time Properties


PR_COMMENT

The PR_COMMENT property contains a comment about the purpose or content of an object.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | All objects
Identifier: | 0x3004
Property type: | PT_TSTRING
Property tag: | 0x3004001E (0x3004001F for Unicode)

Remarks

The content of the string is defined by the messaging user.

See Also

General Object Properties


PR_COMMON_VIEWS_ENTRYID

The PR_COMMON_VIEWS_ENTRYID property contains the entry identifier of the predefined common view folder.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message store objects
Identifier: | 0x35E6
Property type: | PT_BINARY
Property tag: | 0x35E60102

Remarks

The common view folder contains a predefined set of standard view specifiers, while the view folder contains specifiers defined by a messaging user. These folders, which are not visible in the interpersonal message (IPM) hierarchy, can hold many view specifiers, each one stored as a message. A client application can choose to merge the two sets of specifiers and make them both available.

For more information on views, see View Folders.

See Also

Folder Properties, PR_DEFAULT_VIEW_ENTRYID, PR_VIEWS_ENTRYID


PR_COMPANY_NAME

The PR_COMPANY_NAME property contains the recipient's company name.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A16
Property type: | PT_TSTRING
Property tag: | 0x3A16001E (0x3A16001F for Unicode)

Remarks

The PR_COMPANY_NAME property is one of the properties that provide identification and access information about a recipient. These properties are defined by the recipient and the recipient's organization.

See Also

Personal Information Properties


PR_CONTAINER_CLASS

The PR_CONTAINER_CLASS property was originally meant to contain a text string describing the type of a folder.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3613
Property type: | PT_TSTRING
Property tag: | 0x3613001E (0x3613001F for Unicode)

Remarks

Do not use this property. It is not supported in MAPI 1.0.

See Also

Unused Properties


PR_CONTAINER_CONTENTS

The PR_CONTAINER_CONTENTS property contains an embedded contents table object that provides information about a container.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Address book container and folder objects
Identifier: | 0x360F
Property type: | PT_OBJECT
Property tag: | 0x360F000D

Remarks

The PR_CONTAINER_CONTENTS property can be excluded in IMAPIProp::CopyTo operations or included in IMAPIProp::CopyProps operations. As a property of type PT_OBJECT, it cannot be successfully retrieved by the IMAPIProp::GetProps method; its contents should be accessed by the IMAPIProp::OpenProperty method, requesting the IID_IMAPITable interface identifier. Service providers must report it to the IMAPIProp::GetPropList method if it is set, but can optionally report it or not if it is not set.

To retrieve table contents, a client application should call the IMAPIContainer::GetContentsTable method. For more information, see Contents Tables.

The PR_CONTAINER_CONTENTS, PR_CONTAINER_HIERARCHY, and PR_FOLDER_ASSOCIATED_CONTENTS properties are similar in usage. Several MAPI properties provide access to tables:

Property | Table
PR_CONTAINER_CONTENTS | Contents table
PR_CONTAINER_HIERARCHY | Hierarchy table
PR_FOLDER_ASSOCIATED_CONTENTS | Associated contents table
PR_MESSAGE_ATTACHMENTS | Attachment table
PR_MESSAGE_RECIPIENTS | Recipient table

See Also

Table Access Properties


PR_CONTAINER_FLAGS

The PR_CONTAINER_FLAGS property contains a bitmask of flags describing capabilities of an address book container.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Address book container objects
Identifier: | 0x3600
Property type: | PT_LONG
Property tag: | 0x36000003

Remarks

One or more of the following flags can be set for the PR_CONTAINER_FLAGS bitmask:

AB_FIND_ON_OPEN
Displays a dialog box to request a restriction before displaying any contents of the container.
AB_MODIFIABLE
Entries can be added to and removed from the container. This flag does not indicate whether any entries in the container can be modified.
AB_RECIPIENTS
The container can hold recipients. This flag does not indicate whether any recipients are actually present in the container, nor whether they can be added or removed.
AB_SUBCONTAINERS
The container can hold child containers. This flag does not indicate whether any subcontainers are actually present in the container, nor whether they can be added or removed. AB_SUBCONTAINERS must be set for the container to support IMAPIContainer::GetHierarchyTable.
AB_UNMODIFIABLE
Entries cannot be added to or removed from the container. This flag does not indicate whether any entries in the container can be modified.

The AB_FIND_ON_OPEN flag is highly recommended for containers used with online services or with slow connections to servers. When a container is opened that has AB_FIND_ON_OPEN set, a Find dialog box is presented to the user to restrict the displayed messaging users. Even a partial specification limiting the messaging users can dramatically speed up a display of the contents.

Either the AB_MODIFIABLE or AB_UNMODIFIABLE flag must be set. Both flags can be set to indicate that the container does not know whether it can be modified or not, for example if modification depends on the user's access rights. In this case, a client application must attempt a call and examine the return code to determine the container's capabilities. A client typically starts by examining AB_MODIFIABLE. If it is set, the client makes a call that attempts to modify the container and checks the return value.

The AB_MODIFIABLE flag does not indicate what types of entries can be added to the container. To determine this, the client should use the appropriate OpenProperty method to open the container's PR_CREATE_TEMPLATES property. Opening PR_CREATE_TEMPLATES causes the container's one-off table to be returned, listing the kinds of entries that can be created in the container.


PR_CONTAINER_HIERARCHY

The PR_CONTAINER_HIERARCHY property contains an embedded hierarchy table object that provides information about the child containers.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Address book container and folder objects
Identifier: | 0x360E
Property type: | PT_OBJECT
Property tag: | 0x360E000D

Remarks

The PR_CONTAINER_HIERARCHY property can be excluded in IMAPIProp::CopyTo operations or included in IMAPIProp::CopyProps operations. As a property of type PT_OBJECT, it cannot be successfully retrieved by the IMAPIProp::GetProps method; its contents should be accessed by the IMAPIProp::OpenProperty method, requesting the IID_IMAPITable interface identifier. Service providers must report it to the IMAPIProp::GetPropList method if it is set, but can optionally report it or not if it is not set.

To retrieve table contents, a client application should call the IMAPIContainer::GetHierarchyTable method. For more information, see Hierarchy Tables.

The PR_CONTAINER_CONTENTS, PR_CONTAINER_HIERARCHY, and PR_FOLDER_ASSOCIATED_CONTENTS properties are similar in usage. Several MAPI properties provide access to tables:

Property | Table
PR_CONTAINER_CONTENTS | Contents table
PR_CONTAINER_HIERARCHY | Hierarchy table
PR_FOLDER_ASSOCIATED_CONTENTS | Associated contents table
PR_MESSAGE_ATTACHMENTS | Attachment table
PR_MESSAGE_RECIPIENTS | Recipient table

See Also

Table Access Properties


PR_CONTAINER_MODIFY_VERSION

The PR_CONTAINER_MODIFY_VERSION property was originally meant to contain the current modification version for a folder.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3614
Property type: | PT_I8
Property tag: | 0x36140014

Remarks

Do not use this property. It is not supported in MAPI 1.0.

See Also

Unused Properties


PR_CONTENT_CONFIDENTIALITY_ALGORITHM_ID

The PR_CONTENT_CONFIDENTIALITY_ALGORITHM_ID property contains an identifier for the algorithm used to confirm message content confidentiality.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0006
Property type: | PT_BINARY
Property tag: | 0x00060102
Corresponding X.400 attribute: | MH_T_ALGORITHM_ID or MH_T_CONFIDENTIALITY_ALGORITHM

See Also

Content Properties, PR_SECURITY


PR_CONTENT_CORRELATOR

The PR_CONTENT_CORRELATOR property contains a value the message sender can use to match a report with the original message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0007
Property type: | PT_BINARY
Property tag: | 0x00070102
Corresponding X.400 attribute: | MH_T_CONTENT_CORRELATOR

Remarks

The contents of the binary string are defined by the message originator. If set on an outgoing message, the PR_CONTENT_CORRELATOR property should be copied onto any reports generated in response to the message.

See Also

Content Properties


PR_CONTENT_COUNT

The PR_CONTENT_COUNT property contains the number of messages in a folder, as computed by the message store.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Folder objects
May be a column in: | Folder contents tables
Must be a column in: | Folder hierarchy tables
Identifier: | 0x3602
Property type: | PT_LONG
Property tag: | 0x36020003

Remarks

The number contained in the PR_CONTENT_COUNT property does not include associated entries in the folder. PR_CONTENT_UNREAD contains the count of unread messages for the folder. A client application can read but not change PR_CONTENT_COUNT and PR_CONTENT_UNREAD.

See Also

Folder Properties


PR_CONTENT_IDENTIFIER

The PR_CONTENT_IDENTIFIER property contains a key value that enables the message recipient to identify its content.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0008
Property type: | PT_TSTRING
Property tag: | 0x0008001E (0x0008001F for Unicode)
Corresponding X.400 attribute: | MH_T_CONTENT_IDENTIFIER

See Also

Content Properties


PR_CONTENT_INTEGRITY_CHECK

The PR_CONTENT_INTEGRITY_CHECK property contains an ASN.1 content integrity check value that allows a message sender to protect message content from disclosure to unauthorized recipients.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0C00
Property type: | PT_BINARY
Property tag: | 0x0C000102
Corresponding X.400 attribute: | MH_T_INTEGRITY_CHECK

Remarks

The PR_CONTENT_INTEGRITY_CHECK property provides for non-repudiation of message content. In conjunction with PR_MESSAGE_TOKEN it ensures that the content of a message arrives at its destination unchanged.

See Also

Content Properties, PR_MESSAGE_SECURITY_LABEL


PR_CONTENT_LENGTH

The PR_CONTENT_LENGTH property contains a message length, in bytes, passed to a client application or service provider to determine if a message of that length can be delivered.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0009
Property type: | PT_LONG
Property tag: | 0x00090003
Corresponding X.400 attribute: | MH_T_CONTENT_LENGTH

See Also

Content Properties


PR_CONTENT_RETURN_REQUESTED

The PR_CONTENT_RETURN_REQUESTED property contains TRUE if a message should be returned with a nondelivery report.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x000A
Property type: | PT_BOOLEAN
Property tag: | 0x000A000B
Corresponding X.400 attribute: | MH_T_CONTENT_RETURN_REQUESTED

Remarks

If the PR_CONTENT_RETURN_REQUESTED property is not set, MAPI treats it as having a TRUE value.

See Also

Content Properties


PR_CONTENT_UNREAD

The PR_CONTENT_UNREAD property contains the number of unread messages in a folder, as computed by the message store.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Folder objects
May be a column in: | Folder contents tables
Must be a column in: | Folder hierarchy tables
Identifier: | 0x3603
Property type: | PT_LONG
Property tag: | 0x36030003

Remarks

The PR_CONTENT_UNREAD property contains the number of messages in the folder contents table for which the MSGFLAG_READ flag is not set in the PR_MESSAGE_FLAGS property. The PR_CONTENT_COUNT property contains the total message count for the folder. PR_CONTENT_COUNT and PR_CONTENT_UNREAD are read-only to clients.

Some client applications display the heading row of a category differently depending on the value of PR_CONTENT_UNREAD. For example, a client can display a category that includes unread messages in bold. PR_CONTENT_UNREAD cannot be used as a category and an attempt to do so results in the MAPI_E_INVALID_PARAMETER value being returned from the IMAPITable::SortTable method.

See Also

Folder Properties, PR_CONTENT_IDENTIFIER


PR_CONTENTS_SORT_ORDER

The PR_CONTENTS_SORT_ORDER property was originally meant to contain a value specifying the sort order for the columns of a container.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x360D
Property type: | PT_MV_LONG
Property tag: | 0x360D1003

Remarks

Do not use this property. It is not supported in MAPI 1.0.

See Also

Unused Properties, SSortOrder


PR_CONTROL_FLAGS

The PR_CONTROL_FLAGS property contains a bitmask of flags governing the behavior of a control used in a dialog box built from a display table.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | Display tables
Identifier: | 0x3F00
Property type: | PT_LONG
Property tag: | 0x3F000003

Remarks

One or more of the following flags can be set for PR_CONTROL_FLAGS:

DT_ACCEPT_DBCS
The control can have Double-Byte Character Set (DBCS) characters in it. This flag is used with edit controls. It allows multiple-byte character sets.
DT_EDITABLE
The control can be edited; the value associated with the control can be changed. When this flag is not set, the control is read-only. This value is ignored on label, group box, standard push button, multivalued drop down list box and list box controls.
DT_MULTILINE
The edit control can contain multiple lines. This means a return character can be entered within the control. This flag is valid for edit controls only.
DT_PASSWORD_EDIT
Applies to edit controls. The edit control is treated like a password. The value is displayed using asterisks instead of echoing the actual characters entered.
DT_REQUIRED
If the control allows changes (DT_EDITABLE), it must have a value before IMAPIProp::SaveChanges is called.
DT_SET_IMMEDIATE
Enables immediate setting of a value; as soon as a value in the control changes, MAPI calls the SetProps method for the property associated with that control. When this flag is not set, the values are set when the dialog box is dismissed.
DT_SET_SELECTION
When a selection is made within the list box, the index column of that list box is set as a property. Always used with DT_SET_IMMEDIATE.

The PR_CONTROL_FLAGS property is stored in the ulCtlFlags member of a control's DTCTL structure. Most of the control flags apply to all of the controls that allow user input; a few apply only to the edit control. Controls that do not allow user input, such as a button or a label, set 0 for their control flags.

Many of the flag values are self-explanatory. For example, when DT_REQUIRED is set for a control, it must contain a value before the dialog box is allowed to be dismissed. Either the service provider can supply a value through its IMAPIProp implementation or the user can enter one. DT_EDITABLE indicates that the value for the control can be modified. DT_MULTILINE allows the value for an edit control to span multiple lines.

Some control flags are not so obvious in their meaning. When a control sets the DT_SET_IMMEDIATE flag, any changes to its value take affect as soon as the user moves to a new control. MAPI makes a single call to the property interface's IMAPIProp::SetProps method for the control's property. This is different from the default behavior, which is to postpone having changes to control values take effect until after the user selects the OK button or dismisses the dialog box. The DT_SET_IMMEDIATE flag is often used in combination with display table notifications.

The following table lists the types of controls and all of the flag values that can be set for each type.

Control | Valid values for PR_CONTROL_FLAGS
Button | Must be zero
Check box | DT_EDITABLE, DT_SET_IMMEDIATE
Combo box | DT_EDITABLE, DT_REQUIRED, DT_SET_IMMEDIATE
Drop-down list box | DT_EDITABLE, DT_SET_IMMEDIATE
Edit | DT_ACCEPT_DBCS, DT_MULTILINE, DT_EDITABLE, DT_PASSWORD_EDIT, DT_REQUIRED, DT_SET_IMMEDIATE
Group box | Must be zero
Label | Must be zero
List box | Must be zero
Multivalue drop-down list box | Must be zero
Multivalue list box | Must be zero
Tabbed page | Must be zero
Radio button | Must be zero

See Also

Dialog Box Control Properties, DTCTL


PR_CONTROL_ID

The PR_CONTROL_ID property contains a unique identifier for a control used in a dialog box.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | Display tables
Identifier: | 0x3F07
Property type: | PT_BINARY
Property tag: | 0x3F070102

Remarks

The PR_CONTROL_ID property contains a unique identifier for the control. This identifier should contain a GUID structure and a binary value of type LONG. All controls in the dialog box should use the same GUID to identify the service provider, and each control should use a unique LONG value to ensure that the controls do not collide.

PR_CONTROL_ID is used in notifications. For example, notifications sent on the display table must have PR_CONTROL_ID to uniquely identify the control to update.

See Also

Dialog Box Control Properties, DTCTL


PR_CONTROL_STRUCTURE

The PR_CONTROL_STRUCTURE property contains a pointer to a structure for a control used in a dialog box.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | Display tables
Identifier: | 0x3F01
Property type: | PT_BINARY
Property tag: | 0x3F010102

Remarks

The PR_CONTROL_STRUCTURE property represents a long pointer that is cast to one of the control structures. The control structures include:

DTBLBUTTON | DTBLCHECKBOX
DTBLCOMBOBOX | DTBLDDLBX
DTBLEDIT | DTBLGROUPBOX
DTBLLABEL | DTBLLBX
DTBLMVDDLBOX | DTBLMVLISTBOX
DTBLPAGE | DTBLRADIOBUTTON

See Also

Dialog Box Control Properties, DTCTL


PR_CONTROL_TYPE

The PR_CONTROL_TYPE property contains a value indicating a control type for a control used in a dialog box.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | Display tables
Identifier: | 0x3F02
Property type: | PT_LONG
Property tag: | 0x3F020003

Remarks

The PR_CONTROL_TYPE property can have exactly one of the following values:

DTCT_BUTTON
A dialog button control.
DTCT_CHECKBOX
A dialog check box.
DTCT_COMBOBOX
A dialog combo box.
DTCT_DDLBX
A dialog drop-down list box.
DTCT_EDIT
A dialog edit text box.
DTCT_GROUPBOX
A dialog group box.
DTCT_LABEL
A dialog label.
DTCT_LBX
A dialog list box.
DTCT_LISTBOX
A dialog list box.
DTCT_MVDDLBX
A multivalued list box populated by a multivalued property of type string.
DTCT_PAGE
A dialog tabbed page.
DTCT_RADIOBUTTON
A dialog radio button.

See Also

Dialog Box Control Properties, DTCTL


PR_CONVERSATION_INDEX

The PR_CONVERSATION_INDEX property contains a binary value that indicates the relative position of this message within a conversation thread.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0071
Property type: | PT_BINARY
Property tag: | 0x00710102

Remarks

A conversation thread represents a series of messages and replies. The PR_CONVERSATION_INDEX property is usually implemented using concatenated time stamp values. Its use is optional, even if PR_CONVERSATION_TOPIC is set.

MAPI provides the ScCreateConversationIndex function to create or update a conversation index. The function takes the current index value as a counted byte array and returns the index value with a time stamp concatenated onto the end. A message representing a reply to another message should use ScCreateConversationIndex to update PR_CONVERSATION_INDEX.

A message store provider has the option of assuring that PR_CONVERSATION_INDEX is always set on incoming or outgoing messages. It can do this by calling ScCreateConversationIndex, either with the existing value if PR_CONVERSATION_INDEX is set or with NULL if it is not. This action should be taken before IMAPIProp::SaveChanges is called.

All messages that have the same value for PR_CONVERSATION_TOPIC can be sorted on PR_CONVERSATION_INDEX to reveal the hierarchical relationship of the messages.

See Also

Conversation Properties


PR_CONVERSATION_KEY

The PR_CONVERSATION_KEY property is the obsolete precursor of the PR_CONVERSATION_INDEX and PR_CONVERSATION_TOPIC properties.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x000B
Property type: | PT_BINARY
Property tag: | 0x000B0102

Remarks

Do not use this property. Use PR_CONVERSATION_INDEX and PR_CONVERSATION_TOPIC instead.

See Also

Unused Properties


PR_CONVERSATION_TOPIC

The PR_CONVERSATION_TOPIC property contains the topic of the first message in a conversation thread.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0070
Property type: | PT_TSTRING
Property tag: | 0x0070001E (0x0070001F for Unicode)

Remarks

A conversation thread represents a series of messages and replies. The PR_CONVERSATION_TOPIC property is set for the first message in a thread, usually to the PR_NORMALIZED_SUBJECT property. Subsequent messages in the thread should use the same PR_CONVERSATION_TOPIC without modification.

The PR_CONVERSATION_INDEX property indicates the order relationship between subsequent messages and replies. Its use is optional, even if PR_CONVERSATION_TOPIC is set.

A message store provider has the option of assuring that PR_CONVERSATION_TOPIC is always set on incoming or outgoing messages. If PR_CONVERSATION_TOPIC is already set it should not be altered. If not, it can be set to PR_NORMALIZED_SUBJECT. Any action should be taken before IMAPIProp::SaveChanges is called.

See Also

Conversation Properties


PR_CONVERSION_EITS

The PR_CONVERSION_EITS property contains the encoded information types (EITs) that are applied to a message in transit to describe conversions.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x000C
Property type: | PT_BINARY
Property tag: | 0x000C0102
Corresponding X.400 attribute: | IM_CONVERSION_EITS

Remarks

X.400 environments use the PR_CONVERSION_EITS property for both nondelivery reports and delivery reports.

See Also

Conversion Properties


PR_CONVERSION_PROHIBITED

The PR_CONVERSION_PROHIBITED property contains TRUE if message conversions are prohibited by default for the associated messaging user.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x3A03
Property type: | PT_BOOLEAN
Property tag: | 0x3A03000B
Corresponding X.400 attribute: | MH_T_CONVERSION_PROHIBITED

See Also

Conversion Properties


PR_CONVERSION_WITH_LOSS_PROHIBITED

The PR_CONVERSION_WITH_LOSS_PROHIBITED property contains TRUE if a message transfer agent (MTA) is prohibited from making message text conversions that lose information.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x000D
Property type: | PT_BOOLEAN
Property tag: | 0x000D000B
Corresponding X.400 attribute: | MH_T_CONVERSION_LOSS_PROHIBITED

Remarks

An example of the type of conversion being prohibited is the "lossy" mapping from Unicode (two bytes per character) to a single-byte character set.

See Also

Conversion Properties


PR_CONVERTED_EITS

The PR_CONVERTED_EITS property contains an identifier for the types of text in a message after conversion.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x000E
Property type: | PT_BINARY
Property tag: | 0x000E0102
Corresponding X.400 attribute: | MH_T_CONVERTED_EITS

Remarks

The PR_CONVERTED_EITS property indicates which encoded information types (EITs) were used to convert the text components of the message.

See Also

Conversion Properties


PR_CORRELATE

The PR_CORRELATE property contains TRUE if the sender of a message requests the correlation feature of the messaging system.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0E0C
Property type: | PT_BOOLEAN
Property tag: | 0x0E0C000B

Remarks

The PR_CORRELATE property is used to request the correlation of incoming reports with the original sent message. When a transport provider encounters a submitted message with PR_CORRELATE set to TRUE, it sets the PR_CORRELATE_MTSID property to the message transfer system (MTS) identifier for that message.

PR_CORRELATE should be used with messaging systems that support correlation by MTS identifier, such as X.400.

See Also

Message Properties


PR_CORRELATE_MTSID

The PR_CORRELATE_MTSID property contains the message transfer system (MTS) identifier used in correlating reports with sent messages.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0E0D
Property type: | PT_BINARY
Property tag: | 0x0E0D0102

Remarks

When a transport provider encounters a submitted message with the PR_CORRELATE property set to TRUE, it sets the PR_CORRELATE_MTSID property to the MTS identifier for that message. Following transmission, PR_CORRELATE_MTSID is stored with the message in the interpersonal message (IPM) Sent Items folder.

Messaging systems that support correlation by MTS identifier, such as X.400, retain the identifier as part of the transport envelope of the original message and also of any reports generated in response to it. When a report is delivered from such a messaging system, the transport provider sets PR_CORRELATE_MTSID to the original MTS identifier from the report's transport envelope. PR_CORRELATE_MTSID is then stored with the report.

A client application can maintain a search-results folder of all messages having a PR_CORRELATE_MTSID property. When a report comes in for such a message, the client can apply restrictions to the search-results folder, find the original version of the message, and correlate the original message information with the new information.

See Also

Message Properties


PR_COUNTRY

The PR_COUNTRY property contains the name of the recipient's country.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A26
Property type: | PT_TSTRING
Property tag: | 0x3A26001E (0x3A26001F for Unicode)

Remarks

The PR_COUNTRY property is one of the properties that provide identification and access information about a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_CREATE_TEMPLATES

The PR_CREATE_TEMPLATES property contains an embedded table object that contains dialog box template entry identifiers.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Address book container objects
Identifier: | 0x3604
Property type: | PT_OBJECT
Property tag: | 0x3604000D

Remarks

To learn what template objects can be created inside a container, call the IMAPIProp::OpenProperty method on the PR_CREATE_TEMPLATES property. The resulting object is the one-off table that gives the entry identifiers for all the templates you can create inside the container.

To subsequently create the template objects, call the container object's CreateEntry method on the PR_ENTRYID column values from the one-off table.

See Also

Template Properties, IABContainer::CreateEntry, PR_DISPLAY_NAME, PR_DISPLAY_TYPE


PR_CREATION_TIME

The PR_CREATION_TIME property contains the creation date and time for a message.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x3007
Property type: | PT_SYSTIME
Property tag: | 0x30070040

Remarks

A message store sets the PR_CREATION_TIME property for each message that it creates.

See Also

Time Properties, PR_CREATION_VERSION


PR_CREATION_VERSION

The PR_CREATION_VERSION property was originally meant to contain the message store version current at the time a message was created.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x0E19
Property type: | PT_I8
Property tag: | 0x0E190014

Remarks

Do not use this property. It is not supported in MAPI 1.0.

See Also

Unused Properties, PR_CURRENT_VERSION, PR_MODIFY_VERSION


PR_CURRENT_VERSION

The PR_CURRENT_VERSION property was originally meant to contain the current version of a message store.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x0E00
Property type: | PT_I8
Property tag: | 0x0E000014

Remarks

Do not use this property. It is not supported in MAPI 1.0.

See Also

Unused Properties, PR_CREATION_VERSION, PR_MODIFY_VERSION


PR_DEF_CREATE_DL

The PR_DEF_CREATE_DL property contains the template entry identifier for a default distribution list object.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Address book container objects
Identifier: | 0x3611
Property type: | PT_BINARY
Property tag: | 0x36110102

Remarks

Client applications use the PR_DEF_CREATE_DL property to create a distribution list within a container. Support of entry creation is optional for address book containers; those that do not support it are not required to expose this property.

PR_DEF_CREATE_DL specifies an entry that can appear in the PR_CREATE_TEMPLATES property for distribution lists. After obtaining the identifier, the client uses it in a call to the IABContainer::CreateEntry method. The entry represents the template for the default distribution list.

See Also

Template Properties, IABLogon::CompareEntryIDs


PR_DEF_CREATE_MAILUSER

The PR_DEF_CREATE_MAILUSER property contains the template entry identifier for a default messaging user object.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Address book container objects
Identifier: | 0x3612
Property type: | PT_BINARY
Property tag: | 0x36120102

Remarks

Client applications use the PR_DEF_CREATE_MAILUSER property to create a messaging user object within a container. Support of entry creation is optional for address book containers; those that do not support it are not required to expose this property.

PR_DEF_CREATE_MAILUSER specifies an entry that can appear in the PR_CREATE_TEMPLATES property for messaging users. After obtaining the identifier, the client uses it in a call to the IABContainer::CreateEntry method. The entry represents the template for the default messaging user.

See Also

Template Properties, IABLogon::CompareEntryIDs


PR_DEFAULT_PROFILE

The PR_DEFAULT_PROFILE property contains TRUE if a messaging user profile is the MAPI default profile.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Profile section objects
Identifier: | 0x3D04
Property type: | PT_BOOLEAN
Property tag: | 0x3D04000B

Remarks

The PR_DEFAULT_PROFILE property does not appear as a property of any object but only as a column in a profile table. A client application can use the IProfAdmin::SetDefaultProfile method to designate the default profile.

See Also

PR_DEFAULT_STORE


PR_DEFAULT_STORE

The PR_DEFAULT_STORE property contains TRUE if a message store is the default message store in the message store table.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message store objects
Identifier: | 0x3400
Property type: | PT_BOOLEAN
Property tag: | 0x3400000B

Remarks

The PR_DEFAULT_STORE property appears as a column in the message store table. The value is based on PR_RESOURCE_FLAGS.

See Also

PR_RESOURCE_FLAGS


PR_DEFAULT_VIEW_ENTRYID

The PR_DEFAULT_VIEW_ENTRYID property contains the entry identifier of a folder's default view.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Folder objects
Identifier: | 0x3616
Property type: | PT_BINARY
Property tag: | 0x36160102

Remarks

The PR_DEFAULT_VIEW_ENTRYID property is the entry identifier of the folder view that should be set as the initial view. The property need not be set if the "Normal" view is to be used as the initial view.

A client application can obtain PR_DEFAULT_VIEW_ENTRYID at the time it opens the folder and realize significant performance gains. PR_DEFAULT_VIEW_ENTRYID can be used as a shortcut to obtain the default view, instead of opening the associated contents table and submitting a restriction.

A service provider implementation of the IMAPIFolder::CopyFolder method can copy this property when it copies folders.

See Also

Folder Properties, PR_COMMON_VIEWS_ENTRYID, PR_VIEWS_ENTRYID


PR_DEFERRED_DELIVERY_TIME

The PR_DEFERRED_DELIVERY_TIME property contains the date and time at which a message sender wants a message delivered.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x000F
Property type: | PT_SYSTIME
Property tag: | 0x000F0040
Corresponding X.400 attribute: | MH_T_DEFERRED_DELIVERY_TIME

Remarks

MAPI does not perform the deferred delivery; it is an option of the underlying messaging system to handle deferred delivery.

See Also

Time Properties


PR_DELEGATION

The PR_DELEGATION property contains the converted value of the attDelegate workgroup property.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects used in scheduling
Identifier: | 0x007E
Property type: | PT_BINARY
Property tag: | 0x007E0102

Remarks

The PR_DELEGATION property is used for compatibility with earlier versions of Schedule+. TNEF computes it on messages for Schedule+ 7.0 and compatible versions. Client applications should not use PR_DELEGATION.

In inbound messages to Schedule+ 7.0, the workgroup property attDelegate is decoded into PR_DELEGATION. TNEF constructs PR_DELEGATION in current recipient table order. If a client calling TNEF has provided a recipient table for use in the ITnef::EncodeRecips method, that table is used to build the delegation properties.

PR_DELEGATION is not encoded into attDelegate in outbound messages. Instead, attDelegate is built from the PR_RCVD_REPRESENTING_EMAIL_ADDRESS property if the message is generated by Schedule+, and not built at all otherwise.

See Also

Schedule Properties


PR_DELETE_AFTER_SUBMIT

The PR_DELETE_AFTER_SUBMIT property contains TRUE if a client application wants MAPI to delete the associated message after submission.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0E01
Property type: | PT_BOOLEAN
Property tag: | 0x0E01000B

Remarks

A client application uses the PR_DELETE_AFTER_SUBMIT property with the PR_SENTMAIL_ENTRYID property to control what happens to a message after it is submitted. Either one or the other should be set, but not both.

See Also

Message Properties


PR_DELIVER_TIME

The PR_DELIVER_TIME property contains the date and time at which the original message was delivered.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects used for delivery reports
Identifier: | 0x0010
Property type: | PT_SYSTIME
Property tag: | 0x00100040
Corresponding X.400 attribute: | MH_T_DELIVERY_TIME

Remarks

The PR_DELIVER_TIME property is a per-recipient property on a delivery report that indicates the time the original message was delivered to the messaging user for which the delivery report is being generated.

See Also

Time Properties, IMAPISupport::StatusRecips


PR_DELIVERY_POINT

The PR_DELIVERY_POINT property specifies the nature of the functional entity by means of which a message was or would have been delivered to the recipient.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects used on reports
Identifier: | 0x0C07
Property type: | PT_LONG
Property tag: | 0x0C070003
Corresponding X.400 attribute: | MH_T_DELIVERY_POINT

Remarks

The PR_DELIVERY_POINT property can have exactly one of the following values:

MAPI_MH_DP_ML
Delivered to a distribution list, a delivery point which in turn may distribute the message to many recipients.
MAPI_MH_DP_MS
Delivered to a message store instead of directly to a recipient.
MAPI_MH_DP_OTHER_AU
Delivered to an access unit (AU) other than a physical delivery access unit (PDAU), such as a FAX system.
MAPI_MH_DP_PDAU
Delivered to a physical delivery access unit, such as a human postal carrier.
MAPI_MH_DP_PDS_PATRON
Delivered to a physical delivery system patron, such as a conventional postal mailbox.
MAPI_MH_DP_PRIVATE_UA
Delivered to a private user agent (UA), such as a client in an in-house messaging system.
MAPI_MH_DP_PUBLIC_UA
Delivered to a public user agent, or public service provider.

The default value is MAPI_MH_DP_PRIVATE_UA, that is, a MAPI client.

See Also

Report Properties


PR_DELTAX

The PR_DELTAX property contains the width of a dialog box control in standard Windows dialog units.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | Display tables
Identifier: | 0x3F03
Property type: | PT_LONG
Property tag: | 0x3F030003

Remarks

The PR_XPOS, PR_YPOS, PR_DELTAX, and PR_DELTAY properties position and size the dialog box control.

See Also

Dialog Box Control Properties


PR_DELTAY

The PR_DELTAY property contains the height of a dialog box control in standard Windows dialog units.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | Display tables
Identifier: | 0x3F04
Property type: | PT_LONG
Property tag: | 0x3F040003

Remarks

The PR_XPOS, PR_YPOS, PR_DELTAX, and PR_DELTAY properties position and size the dialog box control.

See Also

Dialog Box Control Properties


PR_DEPARTMENT_NAME

The PR_DEPARTMENT_NAME property contains a name for the department in which the recipient works.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A18
Property type: | PT_TSTRING
Property tag: | 0x3A18001E (0x3A18001F for Unicode)

Remarks

The PR_DEPARTMENT_NAME property is one of the properties that provide identification and access information about a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_DEPTH

The PR_DEPTH property represents the relative level of indentation, or depth, of an object in a hierarchy table.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | Contents tables and hierarchy tables
Identifier: | 0x3005
Property type: | PT_LONG
Property tag: | 0x30050003

Remarks

The PR_DEPTH property can also specify the categorization level of a row in a contents table or the hierarchy depth in a hierarchy table. The depth is zero-based, where zero represents the leftmost category. In all cases, the property value represents a relative value rather than an absolute value. In the hierarchy table, for example, the depth value is relative to the container from which the hierarchy table was retrieved. The depth does not represent an absolute depth from the root container.

See Also

Table Row Properties, PR_OBJECT_TYPE, PR_SELECTABLE


PR_DETAILS_TABLE

The PR_DETAILS_TABLE property contains an embedded display table object.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Address book container, distribution list, and messaging user objects
Identifier: | 0x3605
Property type: | PT_OBJECT
Property tag: | 0x3605000D

Remarks

Passing the PR_DETAILS_TABLE property to the IMAPIProp::OpenProperty method for the object returns an IMAPITable interface that allows creation of the display table. MAPI uses this table to display property sheets for an address book object in response to an IAddrBook::Details call.

For more information, see Display Tables.

See Also

IAddrBook::RecipOptions, IMAPISession::MessageOptions, PR_CREATE_TEMPLATES, PR_SEARCH


PR_DISC_VAL

The PR_DISC_VAL property is the obsolete precursor of the PR_DISCRETE_VALUES property.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x004A
Property type: | PT_BOOLEAN
Property tag: | 0x004A000B

Remarks

Do not use this property. Use PR_DISCRETE_VALUES.

See Also

Unused Properties, PR_DISCRETE_VALUES


PR_DISCARD_REASON

The PR_DISCARD_REASON property contains a reason why a message transfer agent (MTA) has discarded a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0011
Property type: | PT_LONG
Property tag: | 0x00110003
Corresponding X.400 attribute: | IM_DISCARD_REASON

Remarks

The reason contained in the PR_DISCARD_REASON property is used in a nondelivery report for the message.

See Also

Report Properties, PR_NDR_REASON_CODE


PR_DISCLOSURE_OF_RECIPIENTS

The PR_DISCLOSURE_OF_RECIPIENTS property contains TRUE if disclosure of recipients is allowed.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0012
Property type: | PT_BOOLEAN
Property tag: | 0x0012000B
Corresponding X.400 attribute: | MH_T_DISCLOSURE_ALLOWED

See Also

Message Properties


PR_DISCRETE_VALUES

The PR_DISCRETE_VALUES property contains TRUE if a nondelivery report applies only to discrete members of a distribution list rather than the entire list.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message recipient subobjects used on nondelivery reports
Identifier: | 0x0E0E
Property type: | PT_BOOLEAN
Property tag: | 0x0E0E000B

Remarks

The PR_DISCRETE_VALUES property is used within a nondelivery report when the message could not be delivered to one or more members of a distribution list. Its purpose is to limit retransmission attempts to only those individual members and not the distribution list as a whole.

The recipient table of a nondelivery report contains entries for all recipients the message could not be delivered to, and also for the distribution lists, if any, to which they belong. The transport provider should set PR_DISCRETE_VALUES to TRUE for each distribution list entry, and it should copy PR_DISPLAY_NAME, PR_ENTRYID, and PR_SEARCH_KEY from the distribution list to PR_ORIGINAL_DISPLAY_NAME, PR_ORIGINAL_ENTRYID, and PR_ORIGINAL_SEARCH_KEY for each member of that distribution list.

PR_DISCRETE_VALUES should not be set at all for any nondelivery report recipient entry other than a distribution list.

See Also

Report Properties


PR_DISPLAY_BCC

The PR_DISPLAY_BCC property contains an ASCII list of the display names of any blind carbon copy (BCC) message recipients, separated by semicolons (;).

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0E02
Property type: | PT_TSTRING
Property tag: | 0x0E02001E (0x0E02001F for Unicode)
Corresponding X.400 attribute: | IM_BLIND_COPY_RECIPIENTS

Remarks

The message store computes the PR_DISPLAY_BCC property on message objects using the IMessage::ModifyRecipients method. The message store also maintains the property so that it always reflects the last saved state of a message. The value is synchronized at the time of every call to the IMAPIProp::SaveChanges method.

If a message has no blind carbon copy recipients, the message store should respond to an IMAPIProp::GetProps call with a return value of S_OK and an empty string for PR_DISPLAY_BCC.

Because of the possible need for localization, MAPI provides these guidelines for all recipient names:

  • All names should be able to be localized.
  • The semicolon should be the character that is used to separate names in the PR_DISPLAY_BCC, PR_DISPLAY_CC, and PR_DISPLAY_TO properties. Semicolons are not permitted within recipient names in MAPI.
  • Clients should translate each semicolon encountered in the PR_DISPLAY_BCC property to a localized separator character before making the property information visible in the user interface.
  • When forwarding messages, clients do not need to translate the separator characters on the blind carbon copy recipient line.

See Also

Recipient List Properties


PR_DISPLAY_CC

The PR_DISPLAY_CC property contains an ASCII list of the display names of any carbon copy (CC) message recipients, separated by semicolons (;).

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0E03
Property type: | PT_TSTRING
Property tag: | 0x0E03001E (0x0E03001F for Unicode)
Corresponding X.400 attribute: | IM_COPY_RECIPIENTS

Remarks

The message store computes the PR_DISPLAY_CC property on message objects using the IMessage::ModifyRecipients method. The message store also maintains the property so that it always reflects the last saved state of a message. The value is synchronized at the time of every call to IMAPIProp::SaveChanges.

If a message has no carbon copy recipients, the message store should respond to an IMAPIProp::GetProps call with a return value of S_OK and an empty string for PR_DISPLAY_CC.

Because of the possible need for localization, MAPI provides these guidelines for all recipient names:

  • All names should be able to be localized.
  • The semicolon should be the character that is used to separate names in the PR_DISPLAY_BCC, PR_DISPLAY_CC, and PR_DISPLAY_TO properties. Semicolons are not permitted within recipient names in MAPI.
  • Clients should translate each semicolon encountered in the PR_DISPLAY_CC property to a localized separator character before making the property information visible in the user interface.
  • When forwarding messages, clients do not need to translate the separator characters on the carbon copy recipient line.

See Also

Recipient List Properties


PR_DISPLAY_NAME

The PR_DISPLAY_NAME property contains the display name for a given MAPI object.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Folder, messaging user, provider, and status objects
Identifier: | 0x3001
Property type: | PT_TSTRING
Property tag: | 0x3001001E (0x3001001F for Unicode)
Corresponding X.400 attribute: | IM_FREE_FORM_NAME

Remarks

Folders require sibling subfolders to have unique display names. For example, if a folder contains two subfolders, the two subfolders cannot use the same value for their PR_DISPLAY_NAME properties. This restriction does not apply to other containers, such as address books and distribution lists.

PR_DISPLAY_NAME is one of the base address properties for all messaging users. For more information on the base address properties, see Base Address Properties.

Service providers should set the value of PR_DISPLAY_NAME so that it contains both the provider type and configuration information. The additional information helps to distinguish between instances of providers of the same type. Unconfigured providers should use a string that names the provider. Configured providers should use the same string followed by a distinguishing string in parentheses. For example, an unconfigured message store provider might set PR_DISPLAY_NAME to:

Personal Information Store

The configured version could then set PR_DISPLAY_NAME to:

Personal Information Store (September 17, 1997)

For status objects, the PR_DISPLAY_NAME property contains the name of the component that can be displayed by the user interface.

Note Semicolons cannot be used within recipient names in MAPI messaging.

See Also

Base Address Properties, PR_TRANSMITTABLE_DISPLAY_NAME


PR_DISPLAY_TO

The PR_DISPLAY_TO property contains an ASCII list of the display names of the primary (To) message recipients, separated by semicolons (;).

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0E04
Property type: | PT_TSTRING
Property tag: | 0x0E04001E (0x0E04001F for Unicode)
Corresponding X.400 attribute: | IM_PRIMARY_RECIPIENTS

Remarks

The message store computes the PR_DISPLAY_TO property on message objects using the IMessage::ModifyRecipients method. The message store also maintains the property so that it always reflects the last saved state of a message. The value is synchronized at the time of every call to the IMAPIProp::SaveChanges method.

If a message has no primary recipients, the message store should respond to an IMAPIProp::GetProps call with a return value of S_OK and an empty string for PR_DISPLAY_TO.

Because of the possible need for localization, MAPI provides these guidelines for all recipient names:

  • All names should be able to be localized.
  • The semicolon should be the character that is used to separate names in the PR_DISPLAY_BCC, PR_DISPLAY_CC, and PR_DISPLAY_TO properties. Semicolons are not permitted within recipient names in MAPI.
  • Clients should translate each semicolon encountered in the PR_DISPLAY_TO property to a localized separator character before making the property information visible in the user interface.
  • When forwarding messages, clients do not need to translate the separator characters on the primary recipient line.

See Also

Recipient List Properties


PR_DISPLAY_TYPE

The PR_DISPLAY_TYPE property contains a value used to associate an icon with a particular row of a table.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | Address book contents tables, address book hierarchy tables, folder hierarchy tables, and one-off tables
Identifier: | 0x3900
Property type: | PT_LONG
Property tag: | 0x39000003

Remarks

The PR_DISPLAY_TYPE property contains a long integer that facilitates special treatment of the table entry based on its type. This special treatment typically consists of displaying an icon, or other display element, associated with the display type.

PR_DISPLAY_TYPE is not used in folder contents tables. Client applications should use a message's PR_MESSAGE_CLASS property and appropriate IMAPIFormInfo interface to get the PR_ICON and PR_MINI_ICON properties for that message.

PR_DISPLAY_TYPE can have exactly one of the following values:

DT_AGENT
An automated agent, such as Quote-Of-The-Day or a weather chart display.
DT_DISTLIST
A distribution list.
DT_FOLDER
Display default folder icon adjacent to folder.
DT_FOLDER_LINK
Display default folder link icon adjacent to folder rather than the default folder icon.
DT_FOLDER_SPECIAL
Display icon for a folder with an application-specific distinction, such as a special type of public folder.
DT_FORUM
A forum, such as a bulletin board service or a public or shared folder.
DT_GLOBAL
A global address book.
DT_LOCAL
A local address book that you share with a small workgroup.
DT_MAILUSER
A typical messaging user.
DT_MODIFIABLE
Modifiable; the container should be denoted as modifiable in the user interface.
DT_NOT_SPECIFIC
Does not match any of the other settings.
DT_ORGANIZATION
A special alias defined for a large group, such as helpdesk, accounting, or blood-drive coordinator.
DT_PRIVATE_DISTLIST
A private, personally administered distribution list.
DT_REMOTE_MAILUSER
A recipient known to be from a foreign or remote messaging system.
DT_WAN
A wide area network address book.

Address book contents tables use the DT_AGENT, DT_DISTLIST, DT_FORUM, DT_MAILUSER, DT_ORGANIZATION, DT_PRIVATE_DISTLIST, and DT_REMOTE_MAILUSER values. Address book hierarchy tables and one-off tables use the DT_GLOBAL, DT_LOCAL, DT_MODIFIABLE, DT_NOT_SPECIFIC, and DT_WAN values. Folder hierarchy tables use the DT_FOLDER, DT_FOLDER_LINK, and DT_FOLDER_SPECIAL values.

If PR_DISPLAY_TYPE is not set, the client should assume the default type appropriate for the table, typically DT_FOLDER, DT_LOCAL, or DT_MAILUSER.

Note All values not documented are reserved for MAPI. Client applications must not define any new values and must be prepared to deal with an undocumented value.

See Also

Table Row Properties


PR_DL_EXPANSION_HISTORY

The PR_DL_EXPANSION_HISTORY property contains a history showing how a distribution list has been expanded during message transmission.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0013
Property type: | PT_BINARY
Property tag: | 0x00130102
Corresponding X.400 attribute: | MH_T_EXPANSION_HISTORY

Remarks

The PR_DL_EXPANSION_HISTORY property is available to receiving client applications if the transport provider has set it. It is also available to the sending client if the message content is returned with a report.

See Also

Message Properties, PR_DL_EXPANSION_PROHIBITED


PR_DL_EXPANSION_PROHIBITED

The PR_DL_EXPANSION_PROHIBITED property contains TRUE if a message transfer agent (MTA) is prohibited from expanding distribution lists.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0014
Property type: | PT_BOOLEAN
Property tag: | 0x0014000B
Corresponding X.400 attribute: | MH_T_EXPANSION_PROHIBITED

See Also

Message Properties, PR_DL_EXPANSION_HISTORY


PR_EMAIL_ADDRESS

The PR_EMAIL_ADDRESS property contains the messaging user's e-mail address.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Distribution list and messaging user objects
Identifier: | 0x3003
Property type: | PT_TSTRING
Property tag: | 0x3003001E (0x3003001F for Unicode)

Remarks

The PR_EMAIL_ADDRESS property is one of the base address properties for all messaging users. It is a null-terminated string whose format has meaning only for the underlying messaging system.

PR_EMAIL_ADDRESS is used in conjunction with the PR_ADDRTYPE and PR_MESSAGE_CLASS properties in addressing messages. The string format is qualified by PR_ADDRTYPE.

Valid PR_EMAIL_ADDRESS examples include:

network/postoffice/user
Bruce@XYZZY.COM
/c=US/a=att/p=Microsoft/o=Finance/ou=Purchasing/s=Furthur/g=Joe

For more information on the base address properties, see Base Address Properties. For more information on address types, see Address Types.

See Also

Base Address Properties


PR_END_DATE

The PR_END_DATE property contains the ending date and time of an appointment as managed by a scheduling application.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects used in scheduling
Identifier: | 0x0061
Property type: | PT_SYSTIME
Property tag: | 0x00610040

Remarks

Scheduling applications should set both the PR_START_DATE and PR_END_DATE properties when sending meeting requests.

See Also

Schedule Properties


PR_ENTRYID

The PR_ENTRYID property contains a MAPI entry identifier used to open and edit properties of a particular MAPI object.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Address book container, distribution list, folder, messaging user, message, message store, and status objects
Identifier: | 0x0FFF
Property type: | PT_BINARY
Property tag: | 0x0FFF0102

Remarks

The PR_ENTRYID property identifies an object for OpenEntry to instantiate and provides access to all of its properties through the appropriate derived interface of IMAPIProp.

PR_ENTRYID is one of the base address properties for all messaging users. For more information on the base address properties, see Base Address Properties.

PR_ENTRYID can contain either a long-term or a short-term identifier. Short-term identifiers are easier and faster to construct, but are limited in their scope and duration, typically to the current session and workstation. They are commonly used for objects of a temporary nature, such as table rows or dialog box entries, and then abandoned. Long-term identifiers are used for objects of a more wide-ranging and long-lasting nature.

PR_ENTRYID is always available through the IMAPIProp::GetProps method following the first call to the IMAPIProp::SaveChanges method. Some service providers can make it available immediately after instantiation. The provider must always return a long-term entry identifier from GetProps. Therefore, to convert a short-term identifier to long-term, simply open the object and get its PR_ENTRYID through GetProps.

The following table summarizes important differences among PR_ENTRYID, PR_RECORD_KEY, and PR_SEARCH_KEY.

Characteristic | PR_ENTRYID | PR_RECORD_KEY | PR_SEARCH_KEY
Required on attachment objects | No | Yes | No
Required on folder objects | Yes | Yes | No
Required on message store objects | Yes | Yes | No
Required on status objects | Yes | No | No
Created by client | No | No | Yes
Available before call to SaveChanges | Maybe | Maybe | Messages — Yes Others — Maybe
Changed in a copy operation | Yes | Yes | No
Changeable by client after a copy | No | No | Yes
Unique within | Entire world | Provider instance | Entire world
Binary comparable (as with memcmp) | No — use IMAPISupport:: CompareEntryIDs | Yes | Yes

See Also

Base Address Properties, ENTRYID, NOTIFICATION, PR_STORE_ENTRYID


PR_EXPIRY_TIME

The PR_EXPIRY_TIME property contains the date and time at which the messaging system can invalidate the content of a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0015
Property type: | PT_SYSTIME
Property tag: | 0x00150040
Corresponding X.400 attribute: | IM_EXPIRY_TIME

Remarks

The PR_EXPIRY_TIME property is used to direct the messaging system in handling delivered interpersonal messages.

See Also

Time Properties


PR_EXPLICIT_CONVERSION

The PR_EXPLICIT_CONVERSION property indicates that a message sender has requested a message content conversion for a particular recipient.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects
Identifier: | 0x0C01
Property type: | PT_LONG
Property tag: | 0x0C010003
Corresponding X.400 attribute: | MH_T_EXPLICIT_CONVERSION

See Also

Conversion Properties


PR_FILTERING_HOOKS

The PR_FILTERING_HOOKS property was originally meant to contain hook identifiers.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3D08
Property type: | PT_BINARY
Property tag: | 0x3D080102

Remarks

Do not use this property. It is not supported in MAPI 1.0.

See Also

Unused Properties


PR_FINDER_ENTRYID

The PR_FINDER_ENTRYID property contains the entry identifier for the folder in which search results are typically created.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message store objects
Identifier: | 0x35E7
Property type: | PT_BINARY
Property tag: | 0x35E70102

Remarks

The entry identifier contained in the PR_FINDER_ENTRYID property has the same format as the ENTRYID structure.

See Also

Folder Properties, PR_ENTRYID


PR_FOLDER_ASSOCIATED_CONTENTS

The PR_FOLDER_ASSOCIATED_CONTENTS property contains an embedded contents table object that provides information about the associated contents table.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Folder objects
Identifier: | 0x3610
Property type: | PT_OBJECT
Property tag: | 0x3610000D

Remarks

The associated contents table represents a subfolder that does not appear in the standard contents table. It contains the folder's associated, or hidden, messages.

The PR_FOLDER_ASSOCIATED_CONTENTS property can be excluded in IMAPIProp::CopyTo operations or included in IMAPIProp::CopyProps operations. As a property of type PT_OBJECT, it cannot be successfully retrieved by the IMAPIProp::GetProps method; its contents should be accessed by the IMAPIProp::OpenProperty method, requesting the IID_IMAPITable interface identifier. Service providers must report it to the IMAPIProp::GetPropList method if it is set, but may optionally report it or not if it is not set.

To retrieve table contents, client applications should call the IMAPIContainer::GetContentsTable method. For more information on folder contents tables, see Contents Tables and Displaying a Folder Contents Table.

The PR_CONTAINER_CONTENTS, PR_CONTAINER_HIERARCHY, and PR_FOLDER_ASSOCIATED_CONTENTS properties are similar in usage. Several MAPI properties provide access to tables:

Property | Table
PR_CONTAINER_CONTENTS | Contents table
PR_CONTAINER_HIERARCHY | Hierarchy table
PR_FOLDER_ASSOCIATED_CONTENTS | Associated contents table
PR_MESSAGE_ATTACHMENTS | Attachment table
PR_MESSAGE_RECIPIENTS | Recipient table

See Also

Table Access Properties, PR_ASSOC_CONTENT_COUNT


PR_FOLDER_TYPE

The PR_FOLDER_TYPE property contains a constant that indicates the folder type.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Folder objects
Identifier: | 0x3601
Property type: | PT_LONG
Property tag: | 0x36010003

Remarks

The PR_FOLDER_TYPE property can have exactly one of the following values:

FOLDER_GENERIC
A generic folder that contains messages and other folders.
FOLDER_ROOT
The root folder of the folder hierarchy table, that is, a folder that has no parent folder.
FOLDER_SEARCH
A folder containing the results of a search, in the form of links to messages that meet search criteria.

The root of a message store should not be confused with the root of the interpersonal message (IPM) subtree in that store. The store's root folder, which has no parent, is obtained by calling the IMsgStore::OpenEntry method with a null entry identifier. The IPM subtree's root folder, which does have a parent, is obtained by using the value of the PR_IPM_SUBTREE_ENTRYID property for the OpenEntry call.

MAPI allows only one root folder per message store. This folder contains messages and other folders. The root folder's PR_PARENT_ENTRYID property contains the folder's own entry identifier.

The information in a search-results folder is mainly stored in its contents table, which contains the same columns as a typical contents table, as well as two extra columns identifying the folder in which each message was found: PR_PARENT_DISPLAY (display name, required) and PR_PARENT_ENTRYID (entry identifier, optional).

For more information on folder types, see Folders.

See Also

Folder Properties


PR_FORM_CATEGORY

The PR_FORM_CATEGORY property contains the category of a form.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Form objects
Identifier: | 0x3309
Property type: | PT_TSTRING
Property tag: | 0x3309001E (0x3309001F for Unicode)

Remarks

The category name is defined by a client application in a way that is appropriate to the application.

See Also

Form Properties


PR_FORM_CATEGORY_SUB

The PR_FORM_CATEGORY_SUB property contains the subcategory of a form, as defined by a client application.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Form objects
Identifier: | 0x3310
Property type: | PT_TSTRING
Property tag: | 0x3310001E (0x3310001F for Unicode)

Remarks

The PR_FORM_CATEGORY_SUB property is subordinate to the main form category provided in the PR_FORM_CATEGORY property.

See Also

Form Properties


PR_FORM_CLSID

The PR_FORM_CLSID property contains the 128-bit OLE globally unique identifier (GUID) of a form.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Form objects
Identifier: | 0x3307
Property type: | PT_CLSID
Property tag: | 0x33070048

Remarks

The MAPIUID structure contains the definition of the unique identifier.

See Also

Form Properties


PR_FORM_CONTACT_NAME

The PR_FORM_CONTACT_NAME property contains the name of a contact for information concerning a form.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Form objects
Identifier: | 0x3308
Property type: | PT_TSTRING
Property tag: | 0x3308001E (0x3308001F for Unicode)

Remarks

The contact typically contains the name of a person or an alias that is responsible for maintaining the form.

See Also

Form Properties


PR_FORM_DESIGNER_GUID

The PR_FORM_DESIGNER_GUID property contains the unique identifier for the object used to design a form.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Form objects
Identifier: | 0x3314
Property type: | PT_CLSID
Property tag: | 0x33140048

Remarks

The PR_FORM_DESIGNER_GUID property usually contains the globally unique identifier of the design program used to create the form. This property can be empty.

The MAPIUID structure contains the definition of the unique identifier.

See Also

Form Properties


PR_FORM_DESIGNER_NAME

The PR_FORM_DESIGNER_NAME property contains the display name for the object used to design the form.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Form objects
Identifier: | 0x3313
Property type: | PT_TSTRING
Property tag: | 0x3313001E (0x3313001F for Unicode)

Remarks

The PR_FORM_DESIGNER_GUID property contains the unique identifier for the form designer object.

See Also

Form Properties


PR_FORM_HIDDEN

The PR_FORM_HIDDEN property contains TRUE if a form is to be suppressed from display by compose menus and dialog boxes.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Form objects
Identifier: | 0x3312
Property type: | PT_BOOLEAN
Property tag: | 0x3312000B

Remarks

Form-related properties are read-only.

See Also

Form Properties


PR_FORM_HOST_MAP

The PR_FORM_HOST_MAP property contains a host map of available forms.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Address book container objects
Identifier: | 0x3311
Property type: | PT_LONG
Property tag: | 0x33110003

Remarks

A client application should update the PR_FORM_HOST_MAP property, along with the PR_DISPLAY_NAME property, when changing the underlying structure in the IMAPIFormProp interface.

See Also

Form Properties


PR_FORM_MESSAGE_BEHAVIOR

The PR_FORM_MESSAGE_BEHAVIOR property contains TRUE if a message should be composed in the current folder.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Form objects
Identifier: | 0x3315
Property type: | PT_BOOLEAN
Property tag: | 0x3315000B

Remarks

A value of FALSE indicates that the message should be composed as any other interpersonal message, that is, in the Outbox folder.

See Also

Form Properties


PR_FORM_VERSION

The PR_FORM_VERSION property contains the version of a form.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Form objects
Identifier: | 0x3306
Property type: | PT_TSTRING
Property tag: | 0x3306001E (0x3306001F for Unicode)

Remarks

The form version is a string indicating what design version is currently in effect for the form. The version is defined and maintained by the form's designer and is not necessarily related to any MAPI component version.

See Also

Form Properties


PR_GENERATION

The PR_GENERATION property contains a generational abbreviation that follows the full name of the recipient.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A05
Property type: | PT_TSTRING
Property tag: | 0x3A05001E (0x3A05001F for Unicode)
Corresponding X.400 attribute: | MH_T_GENERATION

Remarks

The PR_GENERATION property is one of the properties that provide identification and access information about a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

Common PR_GENERATION values include Jr., Sr., and III.

See Also

Personal Information Properties


PR_GIVEN_NAME

The PR_GIVEN_NAME property contains the first name of the recipient.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A06
Property type: | PT_TSTRING
Property tag: | 0x3A06001E (0x3A06001F for Unicode)
Corresponding X.400 attribute: | MH_T_GIVEN_NAME

Remarks

The PR_GIVEN_NAME property is one of the properties that provide identification and access information about a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_GOVERNMENT_ID_NUMBER

The PR_GOVERNMENT_ID_NUMBER property contains a government identifier for the recipient.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A07
Property type: | PT_TSTRING
Property tag: | 0x3A07001E (0x3A07001F for Unicode)

Remarks

The PR_GOVERNMENT_ID_NUMBER property is one of the properties that provide identification and access information about a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

PR_GOVERNMENT_ID_NUMBER is commonly set to a passport number, citizen number, or taxpayer number such as a Social Security number.

See Also

Personal Information Properties


PR_HASATTACH

The PR_HASATTACH property contains TRUE if a message contains at least one attachment.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0E1B
Property type: | PT_BOOLEAN
Property tag: | 0x0E1B000B

Remarks

The message store copies the PR_HASATTACH property from the MSGFLAG_HASATTACH flag of the PR_MESSAGE_FLAGS property. A client application can then use PR_HASATTACH to sort on message attachments in a message viewer.

The value of PR_HASATTACH is updated with the IMAPIProp::SaveChanges method.

See Also

Attachment Properties


PR_HEADER_FOLDER_ENTRYID

The PR_HEADER_FOLDER_ENTRYID property was originally meant to contain the entry identifier that a remote transport provider furnishes for its header folder.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3E0A
Property type: | PT_BINARY
Property tag: | 0x3E0A0102

Remarks

Do not use this property. It is not supported in MAPI 1.0.

For information on obtaining the header folder for the purpose of viewing remote message headers, see Implementing Folders for Remote Transports.

See Also

Unused Properties, PR_ENTRYID, PR_MSG_STATUS


PR_HOME_FAX_NUMBER

The PR_HOME_FAX_NUMBER property contains the telephone number of the recipient's home fax machine.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A25
Property type: | PT_TSTRING
Property tag: | 0x3A25001E (0x3A25001F for Unicode)

Remarks

The PR_HOME_FAX_NUMBER property is one of the properties that provide identification and access information about a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_HOME_TELEPHONE_NUMBER

The PR_HOME_TELEPHONE_NUMBER property contains the primary telephone number of the recipient's home.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A09
Property type: | PT_TSTRING
Property tag: | 0x3A09001E (0x3A09001F for Unicode)

Remarks

The PR_HOME_TELEPHONE_NUMBER property is one of the properties that provide identification and access for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties, PR_HOME2_TELEPHONE_NUMBER


PR_HOME2_TELEPHONE_NUMBER

The PR_HOME2_TELEPHONE_NUMBER property contains a secondary telephone number at the recipient's home.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A2F
Property type: | PT_TSTRING
Property tag: | 0x3A2F001E (0x3A2F001F for Unicode)

Remarks

The PR_HOME2_TELEPHONE_NUMBER property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties, PR_HOME_TELEPHONE_NUMBER


PR_ICON

The PR_ICON property contains a bitmap of a full size icon for a form.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Form objects
Identifier: | 0x0FFD
Property type: | PT_BINARY
Property tag: | 0x0FFD0102

Remarks

The PR_ICON property contains a 32 × 32 pixel image of an icon, the same as the contents of a .ICO file. This property is normally copied from the .ICO file specified in the LargeIcon line of the appropriate [Description] section of the form configuration file.

See Also

Form Properties, PR_MINI_ICON


PR_IDENTITY_DISPLAY

The PR_IDENTITY_DISPLAY property contains the display name for a service provider's identity as defined within a messaging system.

Quick Info

Header file: | MAPITAGS.H
May be a column in: | Status tables
Identifier: | 0x3E00
Property type: | PT_TSTRING
Property tag: | 0x3E00001E (0x3E00001F for Unicode)

Remarks

The PR_IDENTITY_DISPLAY property does not appear as a property on any object but only as a column in a status table. It is part of the identity of the service provider exposing the status table row. The provider's identity typically refers to its account on the server, but can refer to any representation the provider defines within the messaging system.

A service provider furnishing any of the identity properties should furnish all of them. Providers that belong to the same message service should expose the same values for the identity properties.

See Also

Identity Properties, IMAPISession::QueryIdentity


PR_IDENTITY_ENTRYID

The PR_IDENTITY_ENTRYID property contains the entry identifier for a service provider's identity as defined within a messaging system.

Quick Info

Header file: | MAPITAGS.H
May be a column in: | Status tables
Identifier: | 0x3E01
Property type: | PT_BINARY
Property tag: | 0x3E010102

Remarks

The PR_IDENTITY_ENTRYID property does not appear as a property on any object but only as a column in a status table. It is part of the identity of the service provider exposing the status table row. The provider's identity typically refers to its account on the server, but can refer to any representation the provider defines within the messaging system.

PR_IDENTITY_ENTRYID is commonly set to the appropriate address book entry identifier.

A service provider furnishing any of the identity properties should furnish all of them. Providers that belong to the same message service should expose the same values for the identity properties.

See Also

Identity Properties, IMAPISession::QueryIdentity


PR_IDENTITY_SEARCH_KEY

The PR_IDENTITY_SEARCH_KEY property contains the search key for a service provider's identity as defined within a messaging system.

Quick Info

Header file: | MAPITAGS.H
May be a column in: | Status tables
Identifier: | 0x3E05
Property type: | PT_BINARY
Property tag: | 0x3E050102

Remarks

The PR_IDENTITY_SEARCH_KEY property does not appear as a property on any object but only as a column in a status table. It is part of the identity of the service provider exposing the status table row. The provider's identity typically refers to its account on the server, but can refer to any representation the provider defines within the messaging system.

A service provider furnishing any of the identity properties should furnish all of them. Providers that belong to the same message service should expose the same values for the identity properties.

See Also

Identity Properties, IMAPISession::QueryIdentity


PR_IMPLICIT_CONVERSION_PROHIBITED

The PR_IMPLICIT_CONVERSION_PROHIBITED property contains TRUE if a message transfer agent (MTA) is prohibited from making implicit message text conversions.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0016
Property type: | PT_BOOLEAN
Property tag: | 0x0016000B

Remarks

If the PR_IMPLICIT_CONVERSION_PROHIBITED property is TRUE, the messaging system must not perform any content conversion on the message unless it is explicitly requested on a per-recipient basis with the PR_EXPLICIT_CONVERSION property.

See Also

Conversion Properties


PR_IMPORTANCE

The PR_IMPORTANCE property contains a value indicating the message sender's opinion of the importance of a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0017
Property type: | PT_LONG
Property tag: | 0x00170003
Corresponding X.400 attribute: | IM_IMPORTANCE

Remarks

The PR_IMPORTANCE and PR_PRIORITY properties should not be confused. Importance indicates a value to users, while priority indicates the order or speed at which the message should be sent by the messaging system software. Higher priority usually indicates a higher cost. Higher importance usually is associated with a different display by the user interface.

PR_IMPORTANCE can have exactly one of the following values:

IMPORTANCE_LOW
The message has low importance.
IMPORTANCE_HIGH
The message has high importance.
IMPORTANCE_NORMAL
The message has normal importance.

See Also

Criticality Properties


PR_INCOMPLETE_COPY

The PR_INCOMPLETE_COPY property contains TRUE if this message is an incomplete copy of another message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0035
Property type: | PT_BOOLEAN
Property tag: | 0x0035000B
Corresponding X.400 attribute: | IM_INCOMPLETE_COPY

See Also

Message Properties


PR_INITIAL_DETAILS_PANE

The PR_INITIAL_DETAILS_PANE property contains the property page in a property sheet to be displayed first.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | Display tables
Identifier: | 0x3F08
Property type: | PT_LONG
Property tag: | 0x3F080003

Remarks

The PR_INITIAL_DETAILS_PANE property contains the zero-based index of the initial foreground pane that appears when a client application displays a details table for an object that exposes property sheets. The value indicates which page should be displayed first. This property appears in an object from which a display table can be obtained.

See Also

IMAPISupport::DoConfigPropSheet


PR_INITIALS

The PR_INITIALS property contains the initials for parts of the full name of the recipient.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A0A
Property type: | PT_TSTRING
Property tag: | 0x3A0A001E (0x3A0A001F for Unicode)
Corresponding X.400 attribute: | MH_T_INITIALS

Remarks

The PR_INITIALS property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

Examples of PR_INITIALS values are AJT, GMcD, JL, RCKJr, and WMSIII.

See Also

Personal Information Properties


PR_INSTANCE_KEY

The PR_INSTANCE_KEY property contains a value that uniquely identifies a row in a table.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | All tables
Identifier: | 0x0FF6
Property type: | PT_BINARY
Property tag: | 0x0FF60102

Remarks

The PR_INSTANCE_KEY property is a binary value that uniquely identifies a row in a table view. PR_INSTANCE_KEY is a required column in most tables. If a row is included in two views, there are two different instance keys. The instance key of a row may differ each time the table is opened, but remains constant while the table is open. Rows added while a table is in use do not reuse an instance key that was previously used.

Use the PR_ENTRYID or PR_RECORD_KEY properties to correlate all the rows of an expansion. Use PR_INSTANCE_KEY to locate a particular instance within the expansion.

When a multivalued property is expanded in a table, a row is created for each instance of the expansion, that is, for each value of that property. Each row has a unique value for the PR_INSTANCE_KEY property, while all the other columns retain their original values throughout the expansion.

In a categorized sort of a table, rows not corresponding to actual data can be added to the result of the sort. Each such row, like all rows in all tables, has its own unique instance key.

PR_INSTANCE_KEY is also used in table event notifications. The propIndex and propPrior members of the TABLE_NOTIFICATION structure are SPropValue structures holding PR_INSTANCE_KEY values. The propIndex member indicates the row that was added or changed. The propPrior member indicates the row before the added or changed row (PR_NULL indicates a change to the first row).

This value is not copied as part of the display table.

PR_INSTANCE_KEY is a MAPIUID structure. All instance keys can be directly compared as binary values.

See Also

Table Row Properties


PR_IPM_ID

The PR_IPM_ID property was originally meant to contain an X.400 identifier of an interpersonal message.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x0018
Property type: | PT_BINARY
Property tag: | 0x00180102

Remarks

Do not use this property. It is not supported in MAPI 1.0.

See Also

Unused Properties


PR_IPM_OUTBOX_ENTRYID

The PR_IPM_OUTBOX_ENTRYID property contains the entry identifier of the standard interpersonal message (IPM) Outbox folder.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message store objects
Identifier: | 0x35E2
Property type: | PT_BINARY
Property tag: | 0x35E20102

Remarks

Outbound messages are usually created in the Outbox folder. Interpersonal messages should be placed in this folder for submission.

See Also

IPM Properties, PR_ENTRYID


PR_IPM_OUTBOX_SEARCH_KEY

The PR_IPM_OUTBOX_SEARCH_KEY property was originally meant to contain the search key of the standard Outbox folder.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3411
Property type: | PT_BINARY
Property tag: | 0x34110102

Remarks

Do not use this property. It is not supported in MAPI 1.0.

See Also

Unused Properties


PR_IPM_RETURN_REQUESTED

The PR_IPM_RETURN_REQUESTED property contains TRUE if this message should be returned with a report.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0C02
Property type: | PT_BOOLEAN
Property tag: | 0x0C02000B
Corresponding X.400 attribute: | IM_IPM_RETURN_REQUESTED

See Also

Report Properties


PR_IPM_SENTMAIL_ENTRYID

The PR_IPM_SENTMAIL_ENTRYID property contains the entry identifier of the standard interpersonal message (IPM) Sent Items folder.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message store objects
Identifier: | 0x35E4
Property type: | PT_BINARY
Property tag: | 0x35E40102

Remarks

After being sent, interpersonal messages are usually placed in the Sent Items folder. A client can use the PR_IPM_SENTMAIL_ENTRYID property to set the PR_SENTMAIL_ENTRYID property on a submitted message.

See Also

IPM Properties, PR_ENTRYID


PR_IPM_SENTMAIL_SEARCH_KEY

The PR_IPM_SENTMAIL_SEARCH_KEY property was originally meant to contain the search key of the standard Sent Items folder.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3413
Property type: | PT_BINARY
Property tag: | 0x34130102

Remarks

Do not use this property. It is not supported in MAPI 1.0.

See Also

Unused Properties


PR_IPM_SUBTREE_ENTRYID

The PR_IPM_SUBTREE_ENTRYID property contains the entry identifier of the root of the interpersonal message (IPM) folder subtree in the message store's folder tree.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message store objects
Identifier: | 0x35E0
Property type: | PT_BINARY
Property tag: | 0x35E00102

Remarks

The PR_IPM_SUBTREE_ENTRYID property represents the root of the IPM hierarchy. IPM clients should not display any folders that are not subfolders of the folder represented by PR_IPM_SUBTREE_ENTRYID.

See Also

IPM Properties, PR_ENTRYID


PR_IPM_SUBTREE_SEARCH_KEY

The PR_IPM_SUBTREE_SEARCH_KEY property was originally meant to contain the search key of the interpersonal message (IPM) root folder.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3410
Property type: | PT_BINARY
Property tag: | 0x34100102

Remarks

Do not use this property. It is not supported in MAPI 1.0.

See Also

Unused Properties


PR_IPM_WASTEBASKET_ENTRYID

The PR_IPM_WASTEBASKET_ENTRYID property contains the entry identifier of the standard interpersonal message (IPM) Deleted Items folder.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message store objects
Identifier: | 0x35E3
Property type: | PT_BINARY
Property tag: | 0x35E30102

Remarks

A client application should move deleted interpersonal messages to the Deleted Items folder. If the message is already in this folder, or if the PR_IPM_WASTEBASKET_ENTRYID property is not supported, the client should delete the message.

See Also

IPM Properties, PR_ENTRYID


PR_IPM_WASTEBASKET_SEARCH_KEY

The PR_IPM_WASTEBASKET_SEARCH_KEY property was originally meant to contain the search key of the standard Deleted Items folder.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3412
Property type: | PT_BINARY
Property tag: | 0x34120102

Remarks

Do not use this property. It is not supported in MAPI 1.0.

See Also

Unused Properties


PR_ISDN_NUMBER

The PR_ISDN_NUMBER property contains the recipient's ISDN-capable telephone number.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A2D
Property type: | PT_STRING
Property tag: | 0x3A2D001E

Remarks

The PR_ISDN_NUMBER property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_KEYWORD

The PR_KEYWORD property contains a keyword identifying the recipient to the recipient's system administrator.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A0B
Property type: | PT_TSTRING
Property tag: | 0x3A0B001E (0x3A0B001F for Unicode)

Remarks

The PR_KEYWORD property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

The contents of the keyword string property are defined based on the needs of the recipient's organization.

See Also

Personal Information Properties


PR_LANGUAGE

The PR_LANGUAGE property contains a value indicating the language in which the messaging user is writing messages.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A0C
Property type: | PT_TSTRING
Property tag: | 0x3A0C001E (0x3A0C001F for Unicode)

Remarks

The string contains a single two-character country code.

See Also

PR_LANGUAGES


PR_LANGUAGES

The PR_LANGUAGES property contains an ASCII list of the languages incorporated in a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x002F
Property type: | PT_TSTRING
Property tag: | 0x002F001E (0x002F001F for Unicode)
Corresponding X.400 attribute: | IM_LANGUAGES

Remarks

The underlying string is a sequence of two-character country codes separated by commas.

See Also

Message Properties, PR_LANGUAGE


PR_LAST_MODIFICATION_TIME

The PR_LAST_MODIFICATION_TIME property contains the date and time the object or subobject was last modified.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | All objects including attachment subobjects
Identifier: | 0x3008
Property type: | PT_SYSTIME
Property tag: | 0x30080040

Remarks

The PR_LAST_MODIFICATION_TIME property is initially set to the same value as the PR_CREATION_TIME property. Attachment subobjects can update it as necessary by copying the last modification time maintained by the native file system. A client applicatin can set this property until the first call to the IMAPIProp::SaveChanges method. From then on the provider should update PR_LAST_MODIFICATION_TIME during every SaveChanges call.

See Also

Time Properties


PR_LATEST_DELIVERY_TIME

The PR_LATEST_DELIVERY_TIME property contains the latest date and time when a message transfer agent (MTA) should deliver a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0019
Property type: | PT_SYSTIME
Property tag: | 0x00190040
Corresponding X.400 attribute: | MH_T_LATEST_DELIVERY_TIME

Remarks

If an MTA cannot deliver a message by the time the PR_LATEST_DELIVERY_TIME property specifies, it cancels the message without delivery.

See Also

Time Properties


PR_LOCALITY

The PR_LOCALITY property contains the name of the recipient's locality, such as the town or city.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A27
Property type: | PT_TSTRING
Property tag: | 0x3A27001E (0x3A27001F for Unicode)

Remarks

The PR_LOCALITY property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_LOCATION

The PR_LOCATION property contains the location of the recipient in a format that is useful to the recipient's organization.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A0D
Property type: | PT_TSTRING
Property tag: | 0x3A0D001E (0x3A0D001F for Unicode)

Remarks

The PR_LOCATION property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

The contents of PR_LOCATION are defined by the needs of the recipient's organization. For example, some organizations might identify messaging users by specifying the building number and office number.

See Also

Personal Information Properties


PR_MAIL_PERMISSION

The PR_MAIL_PERMISSION property contains TRUE if the messaging user is allowed to send and receive messages.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A0E
Property type: | PT_BOOLEAN
Property tag: | 0x3A0E000B

Remarks

If the PR_MAIL_PERMISSION property is not set, MAPI treats it as having a TRUE value.

An example of PR_MAIL_PERMISSION being set to FALSE is a corporate directory where some of the entries are not e-mail-enabled.


PR_MANAGER_NAME

The PR_MANAGER_NAME property contains the recipient's manager.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A4E
Property type: | PT_TSTRING
Property tag: | 0x3A4E001E (0x3A4E001F for Unicode)

Remarks

The PR_MANAGER_NAME property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_MAPPING_SIGNATURE

The PR_MAPPING_SIGNATURE property contains the mapping signature for named properties of a particular MAPI object.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Objects having named properties
Identifier: | 0x0FF8
Property type: | PT_BINARY
Property tag: | 0x0FF80102

Remarks

It is recommended that objects having named properties expose the PR_MAPPING_SIGNATURE property. A client application should check the PR_MAPPING_SIGNATURE property of both objects when copying named properties from one object to another. Use of this property can minimize translating between copied properties' names and identifiers.

If PR_MAPPING_SIGNATURE does not exist for a given MAPI object, then the object has its own unique mapping of names and identifiers. In this case the client must call the IMAPIProp::GetNamesFromIDs method on the source object and then the IMAPIProp::GetIDsFromNames method on the destination object.

When two objects have the same PR_MAPPING_SIGNATURE value, the client does not need to translate name to identifier and identifier to name. The client can simply call the IMAPIProp::GetProps method on the source and then the IMAPIProp::SetProps method on the destination. This is convenient for clients that perform custom copying of named properties, and for providers implementing the IMAPIProp::CopyTo and IMAPIProp::CopyProps methods.

For more information on named properties and mapping of names and identifiers, see Named Properties.

See Also

General Object Properties, MAPINAMEID


PR_MDB_PROVIDER

The PR_MDB_PROVIDER property contains a provider-defined MAPIUID structure that indicates the type of the message store.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message store objects
Must be a column in: | Message store tables
Identifier: | 0x3414
Property type: | PT_BINARY
Property tag: | 0x34140102

Remarks

The MAPIUID structure identifies the type of message store. The value is computed by message store providers on message store objects and is unique to each provider. It is typically used for browsing through the message store table to find a store of the desired type, such as public folders.

PR_MDB_PROVIDER is analogous to the PR_AB_PROVIDER_ID for address books.

See Also

Provider Properties


PR_MESSAGE_ATTACHMENTS

The PR_MESSAGE_ATTACHMENTS property contains a table of restrictions that can be applied to a contents table to find all messages that contain attachment subobjects meeting the restrictions.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0E13
Property type: | PT_OBJECT
Property tag: | 0x0E13000D

Remarks

The PR_MESSAGE_ATTACHMENTS property can be excluded in IMAPIProp::CopyTo operations or included in IMAPIProp::CopyProps operations. As a property of type PT_OBJECT, it cannot be successfully retrieved by the IMAPIProp::GetProps method; its contents should be accessed by the IMAPIProp::OpenProperty method, requesting the IID_IMAPITable interface identifier. Service providers must report it to the IMAPIProp::GetPropList method if it is set, but may optionally report it or not if it is not set.

To retrieve table contents, a client application should call the IMessage::GetAttachmentTable method. For more information, see Attachment Tables.

PR_MESSAGE_ATTACHMENTS can be used for subobject restriction by specifying it in the SSubRestriction structure. This allows the client to limit the view of a container to messages with attachments meeting given criteria. A message qualifies for viewing if at least one row in its attachments table, that is, one attachment, satisfies the subobject restriction.

Note

Using subobject restriction results in the equivalent of an IMAPISession::OpenEntry call on every message in the table. Depending on the client application and the number of messages to be searched, it can affect performance.

The PR_MESSAGE_ATTACHMENTS and PR_MESSAGE_RECIPIENTS properties are similar in usage. Several MAPI properties provide access to tables:

Property | Table
PR_CONTAINER_CONTENTS | Contents table
PR_CONTAINER_HIERARCHY | Hierarchy table
PR_FOLDER_ASSOCIATED_CONTENTS | Associated contents table
PR_MESSAGE_ATTACHMENTS | Attachment table
PR_MESSAGE_RECIPIENTS | Recipient table

See Also

Table Access Properties


PR_MESSAGE_CC_ME

The PR_MESSAGE_CC_ME property contains TRUE if this messaging user is specifically named as a carbon copy (CC) recipient of this message and is not part of a distribution list.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects
Identifier: | 0x0058
Property type: | PT_BOOLEAN
Property tag: | 0x0058000B

Remarks

The PR_MESSAGE_CC_ME property provides a convenient way to determine whether the user name appears explicitly in the carbon copy recipient list, without examining all entries in the list.

This property also assists automated handling of received messages at the time of receipt. At the transport provider's option, PR_MESSAGE_CC_ME either contains FALSE or is not set if the messaging user is not listed directly in the recipient table.

Message delivery resulting from distribution list expansion or a blind carbon copy designation does not cause this property to be set. The recipient must be explicitly named.

Unsent messages generally do not set the PR_MESSAGE_CC_ME, PR_MESSAGE_RECIP_ME, or PR_MESSAGE_TO_ME properties. If they are present in messages the user can access in public message stores, in other users' private stores, in files on disk, or embedded inside other received messages, they generally contain the values to which they were set the last time a transport provider delivered the message.

See Also

Recipient List Properties


PR_MESSAGE_CLASS

The PR_MESSAGE_CLASS property contains a text string that identifies the sender-defined message class, such as IPM.Note.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Must be a column in: | Folder contents tables
Identifier: | 0x001A
Property type: | PT_TSTRING
Property tag: | 0x001A001E (0x001A001F for Unicode)

Remarks

The message class specifies the type of the message. It determines the set of properties defined for the message, the kind of information the message conveys, and how to handle the message.

The PR_MESSAGE_CLASS property contains ASCII strings concatenated with periods. Each string represents a level of subclassing. For example, IPM.Note is a subclass of IPM and a superclass of IPM.Note.Private.

PR_MESSAGE_CLASS must consist of the ASCII characters 32 through 127 and must not end with a period (ASCII 46). Sort and compare operations must treat it as a case-insensitive string. The maximum possible length is 255 characters, but in order to allow MAPI room to append qualifiers it is recommended that the original length be kept under 128 characters. Note that these lengths are given in characters; on platforms such as Unicode and DBCS (Double-Byte Character Set) the actual byte count could be higher.

Every message is required to furnish the PR_MESSAGE_CLASS property. Normally the client application creating a new message sets PR_MESSAGE_CLASS as soon as IMAPIFolder::CreateMessage returns successfully. But if the property has not been set when the client calls IMAPIProp::SaveChanges, the message store should set it to IPM.

The PR_MESSAGE_CLASS values defined by MAPI are:

IPM.Note for a standard interpersonal message
REPORT.<subject message class>.DR for a delivery report
REPORT.<subject message class>.NDR for a nondelivery report
REPORT.<subject message class>.IPNRN for a read report
REPORT.<subject message class>.IPNNRN for a nonread report

IPM and IPC are intended to be superclasses only, and a message should have at least one subclass qualifier appended before being stored or submitted. For more information on message class usage, see Message Classes. For lists of required and optional properties for message classes, see the subtopics of About Message Properties.

A custom message class can define properties in a reserved range for use with that message class only. For more information, see About Property Identifiers.

Message classes control which receive folder an incoming message is stored in. For more information, see the IMsgStore::GetReceiveFolderTable method.

For more information on using message classes with forms and form servers, see Choosing a Message Class.

See Also

Message Properties


PR_MESSAGE_DELIVERY_ID

The PR_MESSAGE_DELIVERY_ID property contains a message transfer system (MTS) identifier for a message delivered to a client application.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x001B
Property type: | PT_BINARY
Property tag: | 0x001B0102
Corresponding X.400 attribute: | MH_T_MTS_IDENTIFIER

See Also

Message Properties, PR_MESSAGE_SUBMISSION_ID


PR_MESSAGE_DELIVERY_TIME

The PR_MESSAGE_DELIVERY_TIME property contains the date and time a message was delivered.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0E06
Property type: | PT_SYSTIME
Property tag: | 0x0E060040
Corresponding X.400 attribute: | MH_T_DELIVERY_TIME

Remarks

The PR_MESSAGE_DELIVERY_TIME property describes the time the message was stored at the server, rather than the download time when the transport provider copied the message from the server to the local store.

See Also

Time Properties


PR_MESSAGE_DOWNLOAD_TIME

The PR_MESSAGE_DOWNLOAD_TIME property contains the estimated time to download a message from a remote server to a local message store.

Quick Info

Header file: | MAPITAGS.H
May be a column in: | Header folder contents tables
Identifier: | 0x0E18
Property type: | PT_LONG
Property tag: | 0x0E180003

Remarks

The PR_MESSAGE_DOWNLOAD_TIME property is expressed in seconds and represents the best estimate of the time it would take a remote transport provider to download a given message from its current location to a message store local to the client viewing the header folder. The remote transport provider typically calculates PR_MESSAGE_DOWNLOAD_TIME by dividing the value of the PR_MESSAGE_SIZE property by the speed of the communications link in bytes per second. If the provider cannot calculate the download time, for example if it does not know the link speed, it should furnish a PT_ERROR value such as MAPI_E_NO_SUPPORT for this column in the header folder contents table.

See Also

Remote Transfer Properties


PR_MESSAGE_FLAGS

The PR_MESSAGE_FLAGS property contains a bitmask of flags indicating the origin and current state of a message.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0E07
Property type: | PT_LONG
Property tag: | 0x0E070003

Remarks

The PR_MESSAGE_FLAGS property is a nontransmittable message property exposed at both the sending and receiving ends of a transmission, with different values depending upon the client application or store provider involved. This property is initialized by the client or message store provider when a message is created and saved for the first time and then updated periodically by the message store provider, a transport provider, and the MAPI spooler as the message is processed and its state changes.

PR_MESSAGE_FLAGS exists on a message both before and after submission, and on all copies of the received message. Although it is not a recipient property, it is exposed differently to each recipient according to whether it has been read or modified by that recipient.

One or more of the following flags can be set for PR_MESSAGE_FLAGS:

MSGFLAG_ASSOCIATED
The message is an associated message of a folder. The client or provider has read-only access to this flag. The MSGFLAG_READ flag is ignored for associated messages, which do not retain a read/unread state.
MSGFLAG_FROMME
The messaging user sending was the messaging user receiving the message. The client or provider has read/write access to this flag until the first IMAPIProp::SaveChanges call and read-only thereafter. This flag is meant to be set by the transport provider.
MSGFLAG_HASATTACH
The message has at least one attachment. This flag corresponds to the message's PR_HASATTACH property. The client has read-only access to this flag.
MSGFLAG_NRN_PENDING
A nonread report needs to be sent for the message. The client or provider has read-only access to this flag.
MSGFLAG_ORIGIN_INTERNET
The incoming message arrived over the Internet. It originated either outside the organization or from a source the gateway cannot consider trusted. The client should display an appropriate message to the user. Transport providers set this flag; the client has read-only access.
MSGFLAG_ORIGIN_MISC_EXT
The incoming message arrived over an external link other than X.400 or the Internet. It originated either outside the organization or from a source the gateway cannot consider trusted. The client should display an appropriate message to the user. Transport providers set this flag; the client has read-only access.
MSGFLAG_ORIGIN_X400
The incoming message arrived over an X.400 link. It originated either outside the organization or from a source the gateway cannot consider trusted. The client should display an appropriate message to the user. Transport providers set this flag; the client has read-only access.
MSGFLAG_READ
The message is marked as having been read. This can occur as the result of a call at any time to IMessage::SetReadFlag or IMAPIFolder::SetReadFlags. Clients can also set this flag by calling a message's IMAPIProp::SetProps method before the message has been saved for the first time. This flag is ignored if the MSGFLAG_ASSOCIATED flag is set.
MSGFLAG_RESEND
The message includes a request for a resend operation with a nondelivery report. The client or provider has read/write access to this flag until the first IMAPIProp::SaveChanges call and read-only thereafter.
MSGFLAG_RN_PENDING
A read report needs to be sent for the message. The client or provider has read-only access to this flag.
MSGFLAG_SUBMIT
The message is marked for sending as a result of a call to IMessage::SubmitMessage. Message store providers set this flag; the client has read-only access.
MSGFLAG_UNMODIFIED
The outgoing message has not been modified since the first time that it was saved; the incoming message has not been modified since it was delivered.
MSGFLAG_UNSENT
The message is still being composed. It is saved, but has not been sent. The client or provider has read/write access to this flag until the first IMAPIProp::SaveChanges call and read-only thereafter. If a client doesn't set this flag by the time the message is sent, the message store provider sets it when IMessage::SubmitMessage is called. Typically, this flag is cleared after the message is sent.

A client or message store provider can check the current state of the message at any time by calling the IMAPIProp::GetProps method to read the flag values. The client or provider can also call the IMAPIProp::SetProps method to change any flags that currently have read/write access.

Several of the flags are always read-only. Some are read/write until the first call to the IMAPIProp::SaveChanges method and thereafter become read-only as far as IMAPIProp::SetProps is concerned. One of these, MSGFLAG_READ, can be changed later through IMessage::SetReadFlag or IMAPIFolder::SetReadFlags.

The initial values for PR_MESSAGE_FLAGS are typically MSGFLAG_UNSENT and MSGFLAG_UNMODIFIED to indicate a message that has not yet been sent or changed. When a message is saved for the second time, the message store provider clears the MSGFLAG_UNMODIFIED flag. Another value that a message store provider can set when a message is saved is the MSGFLAG_HASATTACH flag, indicating that the message has one or more attachments. The PR_HASATTACH property is computed from this setting.

When a client calls the IMessage::SubmitMessage method to send the message, the message store provider makes a copy of it for the MAPI spooler and updates PR_MESSAGE_FLAGS by setting the MSGFLAG_SUBMIT flag. The message store provider also sets MSGFLAG_UNSENT if it is not yet set. MSGFLAG_SUBMIT indicates that SubmitMessage has been called, beginning the send process, and that the message is now read-only to the client. MSGFLAG_UNSENT indicates that the MAPI spooler is handling the message. If the send process is canceled, the message store provider resets this flag.

When the message is given to a transport provider for delivery, the transport provider sets the MSGFLAG_FROMME flag if the sender had the same account on the messaging server as the message was received on. Transport providers set MSGFLAG_FROMME for an incoming message that was sent by the currently logged on user. A client can use this value to determine that it is more appropriate to show recipient names in the contents table of the Sent Items folder than sender names. Messages that have been saved during the composition process and not yet sent should also be displayed with recipient names rather than sender names.

For an incoming message, a message store provider clears the MSGFLAG_READ flag to reset its read status. A client can set or clear the MSGFLAG_READ flag when it is necessary to change the read status and control the sending of read and nonread reports, by calling either the message's IMessage::SetReadFlag method or its folder's IMAPIFolder::SetReadFlags method. The main difference between these methods, other than the object implementing them, is that the folder method can affect one, several, or all of the messages in the folder. The message method affects a single message.

A client should also test an incoming message for the MSGFLAG_ORIGIN_X400, MSGFLAG_ORIGIN_INTERNET, and MSGFLAG_ORIGIN_MISC_EXT flags. These flags are set by the inbound transport provider and indicate that the message arrived from a source that the gateway cannot consider trusted. This means the message originated either outside the organization, or internally but from a workstation not known to the gateway. In any case, the identity of the sender may not be confirmed, and there is a risk of introducing a computer virus into the organization. The client should display a warning message to the user and offer an option of deleting the message without opening it.

Message store providers set the MSGFLAG_UNMODIFIED flag for incoming messages. MSGFLAG_UNMODIFIED indicates that a message has not been changed since delivery. A client cannot clear this value after it has been set by a message store provider.

See Also

Message Properties, IMsgStore::AbortSubmit


PR_MESSAGE_RECIP_ME

The PR_MESSAGE_RECIP_ME property contains TRUE if this messaging user is specifically named as a primary (To), carbon copy (CC), or blind carbon copy (BCC) recipient of this message and is not part of a distribution list.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects
Identifier: | 0x0059
Property type: | PT_BOOLEAN
Property tag: | 0x0059000B

Remarks

The PR_MESSAGE_RECIP_ME property provides a convenient way to determine whether the user name appears explicitly in the recipient list, without examining all entries in the list. The value represents the logical OR operation of the properties PR_MESSAGE_CC_ME and PR_MESSAGE_TO_ME, and the BCC information (which does not otherwise appear in a property).

PR_MESSAGE_RECIP_ME assists automated handling of received messages at the time of receipt. At the transport provider's option, this property either contains FALSE or is not included if the messaging user is not listed directly in the recipient table.

Message delivery resulting from distribution list expansion does not cause this property to be set. The recipient must be explicitly named.

Unsent messages generally do not set the PR_MESSAGE_CC_ME, PR_MESSAGE_RECIP_ME, or PR_MESSAGE_TO_ME properties. If they are present in messages the user can access in public message stores, in other users' private stores, in files on disk, or embedded inside other received messages, they generally contain the values to which they were set the last time a transport provider delivered the message.

See Also

Recipient List Properties


PR_MESSAGE_RECIPIENTS

The PR_MESSAGE_RECIPIENTS property contains a table of restrictions that can be applied to a contents table to find all messages that contain recipient subobjects meeting the restrictions.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0E12
Property type: | PT_OBJECT
Property tag: | 0x0E12000D

Remarks

The PR_MESSAGE_RECIPIENTS property can be excluded in IMAPIProp::CopyTo operations or included in IMAPIProp::CopyProps operations. As a property of type PT_OBJECT, it cannot be successfully retrieved by the IMAPIProp::GetProps method; its contents should be accessed by the IMAPIProp::OpenProperty method, requesting the IID_IMAPITable interface identifier. Service providers must report it to the IMAPIProp::GetPropList method if it is set, but may optionally report it or not if it is not set.

To retrieve table contents, a client application should call the IMessage::GetRecipientTable method. For more information, see Recipient Tables.

PR_MESSAGE_RECIPIENTS can be used for subobject restriction by specifying it in the SSubRestriction structure. This enables a client to limit the view of a container to messages with recipients meeting given criteria. A message qualifies for viewing if at least one row in its recipient table, that is, one recipient satisfies the subobject restriction.

Note Using subobject restriction results is the equivalent of an IMAPISession::OpenEntry call on every message in the table. Depending on the client application and the number of messages to be searched, it can affect performance.

The PR_MESSAGE_ATTACHMENTS and PR_MESSAGE_RECIPIENTS properties are similar in usage. Several MAPI properties provide access to tables:

Property | Table
PR_CONTAINER_CONTENTS | Contents table
PR_CONTAINER_HIERARCHY | Hierarchy table
PR_FOLDER_ASSOCIATED_CONTENTS | Associated contents table
PR_MESSAGE_ATTACHMENTS | Attachment table
PR_MESSAGE_RECIPIENTS | Recipient table

See Also

Table Access Properties


PR_MESSAGE_SECURITY_LABEL

The PR_MESSAGE_SECURITY_LABEL property contains a security label for a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x001E
Property type: | PT_BINARY
Property tag: | 0x001E0102
Corresponding X.400 attribute: | MH_T_SECURITY_LABEL

Remarks

The PR_MESSAGE_SECURITY_LABEL property provides the basis on which the PR_MESSAGE_TOKEN property protects a message. Its association with the message content is guaranteed by the token.

See Also

Message Properties, PR_CONTENT_INTEGRITY_CHECK


PR_MESSAGE_SIZE

The PR_MESSAGE_SIZE property contains the sum, in bytes, of the sizes of all properties on a message object.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0E08
Property type: | PT_LONG
Property tag: | 0x0E080003

Remarks

It is recommended that message objects expose the PR_MESSAGE_SIZE property. The message size indicates the approximate number of bytes transferred when the message is moved from one message store to another. Being the sum of the sizes of all properties on the message object, it is usually considerably greater than the message text alone.

Most message store providers compute the PR_MESSAGE_SIZE property for messages that they handle. However, some message store providers do not support this property. In any case, PR_MESSAGE_SIZE is not available until the IMAPIProp::SaveChanges or IMessage::SubmitMessage method has been called.

See Also

Message Properties, PR_ATTACH_SIZE


PR_MESSAGE_SUBMISSION_ID

The PR_MESSAGE_SUBMISSION_ID property contains a message transfer system (MTS) identifier for the message transfer agent (MTA).

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0047
Property type: | PT_BINARY
Property tag: | 0x00470102
Corresponding X.400 attribute: | MH_T_MTS_IDENTIFIER

Remarks

The PR_MESSAGE_SUBMISSION_ID property is returned by the MTA upon successful completion of message submission. Any future contact with the MTA regarding this message, such as requesting cancellation, uses the MTS identifier in the PR_MESSAGE_SUBMISSION_ID property.

See Also

Message Properties, PR_MESSAGE_DELIVERY_ID


PR_MESSAGE_TO_ME

The PR_MESSAGE_TO_ME property contains TRUE if this messaging user is specifically named as a primary (To) recipient of this message and is not part of a distribution list.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects
Identifier: | 0x0057
Property type: | PT_BOOLEAN
Property tag: | 0x0057000B

Remarks

The PR_MESSAGE_TO_ME property provides a convenient way to determine whether the user name appears explicitly in the primary recipient list, without examining all entries in the list.

This property also assists automated handling of received messages at the time of receipt. At the transport provider's option, PR_MESSAGE_TO_ME either contains FALSE or is not included if the messaging user is not listed directly in the recipient table.

Message delivery resulting from distribution list expansion or a blind carbon copy designation does not cause this property to be set. The recipient must be explicitly named.

Unsent messages generally do not set the PR_MESSAGE_CC_ME, PR_MESSAGE_RECIP_ME, or PR_MESSAGE_TO_ME properties. If they are present in messages the user can access in public message stores, in other users' private stores, in files on disk, or embedded inside other received messages, they generally contain the values to which they were set the last time a transport provider delivered the message.

See Also

Recipient List Properties


PR_MESSAGE_TOKEN

The PR_MESSAGE_TOKEN property contains an ASN.1 security token for a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0C03
Property type: | PT_BINARY
Property tag: | 0x0C030102
Corresponding X.400 attribute: | MH_T_TOKEN

Remarks

The PR_MESSAGE_TOKEN property conveys protected security-related information from its originator to its recipient. In conjunction with PR_MESSAGE_SECURITY_LABEL it guarantees the label's association with the message content. In conjunction with PR_CONTENT_INTEGRITY_CHECK it verifies that the message content is unchanged.

See Also

Message Properties


PR_MHS_COMMON_NAME

The PR_MHS_COMMON_NAME property contains the common name of a messaging user for use in a message header.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x3A0F
Property type: | PT_TSTRING
Property tag: | 0x3A0F001E (0x3A0F001F for Unicode)
Corresponding X.400 attribute: | MH_T_COMMON_NAME

See Also

Supplemental Name Properties, PR_DISPLAY_NAME


PR_MINI_ICON

The PR_MINI_ICON property contains a bitmap of a half-size icon for a form.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Form objects
Identifier: | 0x0FFC
Property type: | PT_BINARY
Property tag: | 0x0FFC0102

Remarks

The PR_MINI_ICON property contains a 32 × 32 pixel image of an icon, the same as the contents of a .ICO file, but only the upper left 16 × 16 pixels are considered significant. This property is normally copied from the .ICO file specified in the SmallIcon line of the appropriate [Description] section of the form configuration file.

Note Some platforms do not support 16 × 16 pixel icons. The 32 × 32 format of PR_MINI_ICON is usable in such a case but client applications should be aware of display inconsistencies.

See Also

Form Properties, PR_ICON


PR_MOBILE_TELEPHONE_NUMBER

The PR_MOBILE_TELEPHONE_NUMBER property contains the recipient's cellular telephone number.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A1C
Property type: | PT_TSTRING
Property tag: | 0x3A1C001E (0x3A1C001F for Unicode)

Remarks

The PR_MOBILE_TELEPHONE_NUMBER property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

MAPI also supports the PR_CELLULAR_TELEPHONE_NUMBER property that is synonymous with PR_MOBILE_TELEPHONE_NUMBER.

See Also

Personal Information Properties


PR_MODIFY_VERSION

The PR_MODIFY_VERSION property was originally meant to contain the message store version current at the time the message was last modified.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x0E1A
Property type: | PT_I8
Property tag: | 0x0E1A0014

Remarks

Do not use this property. It is not supported in MAPI 1.0.

See Also

Unused Properties, PR_CREATION_VERSION, PR_CURRENT_VERSION


PR_MSG_STATUS

The PR_MSG_STATUS property contains a 32-bit bitmask of flags defining the status of a message in a contents table.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | Message store contents tables
Identifier: | 0x0E17
Property type: | PT_LONG
Property tag: | 0x0E170003

Remarks

A message can exist in a contents table and in one or more search-results tables, and each instance of the message can have a different status. The PR_MSG_STATUS property should not be considered a property on a message but a column in a contents table.

A client application can set one or more of the following flags in PR_MSG_STATUS:

MSGSTATUS_ANSWERED
The message has been replied to.
MSGSTATUS_DELMARKED
The message has been marked for subsequent deletion.
MSGSTATUS_DRAFT
The message is in draft revision status.
MSGSTATUS_HIDDEN
The message is to be suppressed from recipients' folder displays.
MSGSTATUS_HIGHLIGHTED
The message is to be highlighted in recipients' folder displays.
MSGSTATUS_REMOTE_DELETE
The message has been marked for deletion at the remote message store without downloading to the local client.
MSGSTATUS_REMOTE_DOWNLOAD
The message has been marked for downloading from the remote message store to the local client.
MSGSTATUS_TAGGED
The message has been tagged for a client-defined purpose.

The MSGSTATUS_DELMARKED, MSGSTATUS_HIDDEN, MSGSTATUS_HIGHLIGHTED, and MSGSTATUS_TAGGED flags are defined by the client. Transport and store providers pass these bits without any action.

Clients can interpret these values in any way that is appropriate for their applications. One way that many clients use the PR_MSG_STATUS property is to display messages marked for deletion with a representative icon.

A remote viewer client can set MSGSTATUS_REMOTE_DELETE or MSGSTATUS_REMOTE_DOWNLOAD on messages in the header folder presented to it by the remote transport provider. The client application can examine each message header in this folder to determine whether the message should be downloaded or deleted at the remote message store. It then uses the IMAPIFolder::SetMessageStatus method to set the appropriate flag. SetMessageStatus is the only way to set any of the PR_MSG_STATUS flags; the IMAPIProp::SetProps method cannot be used. To retrieve the PR_MSG_STATUS property, clients call IMAPIFolder::GetMessageStatus rather than IMAPIProp::GetProps. For more information on remote viewing and remote transport providers, see Remote Transport Architecture.

Bits 16 through 31 (0x10000 through 0x80000000) of PR_MSG_STATUS are available for use by the interpersonal message (IPM) client application. All other bits are reserved for use by MAPI; those not defined in the preceding table should be initially set to zero and not altered subsequently.

See Also

Message Properties, IMAPITable::QueryRows


PR_NDR_DIAG_CODE

The PR_NDR_DIAG_CODE property contains a diagnostic code that forms part of a nondelivery report.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Recipient subobjects within nondelivery report message objects
Identifier: | 0x0C05
Property type: | PT_LONG
Property tag: | 0x0C050003
Corresponding X.400 attribute: | MH_T_NON_DELIVERY_DIAGNOSTIC

Remarks

The PR_NDR_DIAG_CODE property can have exactly one of the following values:

MAPI_DIAG_ALPHABETIC_CHARACTER_LOST
MAPI_DIAG_CONTENT_SYNTAX_IN_ERROR
MAPI_DIAG_CONTENT_TOO_LONG
MAPI_DIAG_CONTENT_TYPE_UNSUPPORTED
MAPI_DIAG_CONVERSION_LOSS_PROHIB
MAPI_DIAG_CONVERSION_UNSUBSCRIBED
MAPI_DIAG_CRITICAL_FUNC_UNSUPPORTED
MAPI_DIAG_EITS_UNSUPPORTED
MAPI_DIAG_EXPANSION_FAILED
MAPI_DIAG_EXPANSION_PROHIBITED
MAPI_DIAG_IMPRACTICAL_TO_CONVERT
MAPI_DIAG_LENGTH_CONSTRAINT_VIOLATD
MAPI_DIAG_LINE_TOO_LONG
MAPI_DIAG_LOOP_DETECTED
MAPI_DIAG_MAIL_ADDRESS_INCOMPLETE
MAPI_DIAG_MAIL_ADDRESS_INCORRECT
MAPI_DIAG_MAIL_FORWARDING_PROHIB
MAPI_DIAG_MAIL_FORWARDING_UNWANTED
MAPI_DIAG_MAIL_NEW_ADDRESS_UNKNOWN
MAPI_DIAG_MAIL_OFFICE_INCOR_OR_INVD
MAPI_DIAG_MAIL_ORGANIZATION_EXPIRED
MAPI_DIAG_MAIL_RECIPIENT_DECEASED
MAPI_DIAG_MAIL_RECIPIENT_DEPARTED
MAPI_DIAG_MAIL_RECIPIENT_MOVED
MAPI_DIAG_MAIL_RECIPIENT_TRAVELLING
MAPI_DIAG_MAIL_RECIPIENT_UNKNOWN
MAPI_DIAG_MAIL_REFUSED
MAPI_DIAG_MAIL_UNCLAIMED
MAPI_DIAG_MAXIMUM_TIME_EXPIRED
MAPI_DIAG_MTS_CONGESTED
MAPI_DIAG_MULTIPLE_INFO_LOSSES
MAPI_DIAG_NO_BILATERAL_AGREEMENT
MAPI_DIAG_NO_DIAGNOSTIC
MAPI_DIAG_NUMBER_CONSTRAINT_VIOLATD
MAPI_DIAG_OR_NAME_AMBIGUOUS
MAPI_DIAG_OR_NAME_UNRECOGNIZED
MAPI_DIAG_PAGE_TOO_LONG
MAPI_DIAG_PARAMETERS_INVALID
MAPI_DIAG_PICTORIAL_SYMBOL_LOST
MAPI_DIAG_PROHIBITED_TO_CONVERT
MAPI_DIAG_PUNCTUATION_SYMBOL_LOST
MAPI_DIAG_REASSIGNMENT_PROHIBITED
MAPI_DIAG_RECIPIENT_UNAVAILABLE
MAPI_DIAG_REDIRECTION_LOOP_DETECTED
MAPI_DIAG_RENDITION_UNSUPPORTED
MAPI_DIAG_SECURE_MESSAGING_ERROR
MAPI_DIAG_SUBMISSION_PROHIBITED
MAPI_DIAG_TOO_MANY_RECIPIENTS

See Also

Report Properties, PR_NDR_REASON_CODE


PR_NDR_REASON_CODE

The PR_NDR_REASON_CODE property contains an encoded reason for nondelivery that forms part of a nondelivery report.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Recipient subobjects within nondelivery report message objects
Identifier: | 0x0C04
Property type: | PT_LONG
Property tag: | 0x0C040003
Corresponding X.400 attribute: | MH_T_NON_DELIVERY_REASON

See Also

Report Properties, PR_NDR_DIAG_CODE


PR_NON_RECEIPT_NOTIFICATION_REQUESTED

The PR_NON_RECEIPT_NOTIFICATION_REQUESTED property contains TRUE if a message sender wants notification of non-receipt for a specified recipient.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects, recipient subobjects
Identifier: | 0x0C06
Property type: | PT_BOOLEAN
Property tag: | 0x0C06000B
Corresponding X.400 attribute: | IM_NOTIFICATION_REQUEST

Remarks

If the PR_NON_RECEIPT_NOTIFICATION_REQUESTED property contains FALSE and the PR_READ_RECEIPT_REQUESTED property contains TRUE, the service provider can override PR_NON_RECEIPT_NOTIFICATION_REQUESTED and generate a nondelivery report.

See Also

Report Properties


PR_NON_RECEIPT_REASON

The PR_NON_RECEIPT_REASON property contains reasons why a message was not received that forms part of a nondelivery report.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Nondelivery report message objects
Identifier: | 0x003E
Property type: | PT_LONG
Property tag: | 0x003E0003
Corresponding X.400 attribute: | IM_NON_RECEIPT_REASON

Remarks

Reasons can include, for example, that the message was discarded.

See Also

Report Properties, PR_NDR_DIAG_CODE


PR_NORMALIZED_SUBJECT

The PR_NORMALIZED_SUBJECT property contains the message subject with any prefix removed.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0E1D
Property type: | PT_TSTRING
Property tag: | 0x0E1D001E (0x0E1D001F for Unicode)
Corresponding X.400 attribute: | IM_SUBJECT

Remarks

The PR_NORMALIZED_SUBJECT property is computed by message store or transport providers from the PR_SUBJECT and PR_SUBJECT_PREFIX properties in the following manner.

  • If PR_SUBJECT_PREFIX is present and is an initial substring of PR_SUBJECT, PR_NORMALIZED_SUBJECT is set to the contents of PR_SUBJECT with the prefix removed.
  • If PR_SUBJECT_PREFIX is present, but it is not an initial substring of PR_SUBJECT, PR_SUBJECT_PREFIX is deleted and recalculated from PR_SUBJECT using the following rule:

    If the string contained in PR_SUBJECT begins with one to three non-numeric characters followed by a colon and a space, then the string together with the colon and the blank becomes the prefix. Numbers, blanks, and punctuation characters are not valid prefix characters.

  • If PR_SUBJECT_PREFIX is not present, it is calculated from PR_SUBJECT using the rule outlined in the previous step. PR_NORMALIZED_SUBJECT then is set to the contents of PR_SUBJECT with the prefix removed.

Note When PR_SUBJECT_PREFIX is an empty string, PR_SUBJECT and PR_NORMALIZED_SUBJECT are the same.

Ultimately, PR_NORMALIZED_SUBJECT should be the part of PR_SUBJECT following the prefix. If there is no prefix, PR_NORMALIZED_SUBJECT becomes the same as PR_SUBJECT.

PR_SUBJECT_PREFIX and PR_NORMALIZED_SUBJECT should be computed as part of the IMAPIProp::SaveChanges implementation. A client application should not prompt the IMAPIProp::GetProps method for their values until they have been committed by an IMAPIProp::SaveChanges call.

The subject properties are typically small strings of fewer than 256 characters, and a message store provider is not obligated to support the OLE IStream interface on them. The client should always attempt access through the IMAPIProp interface first, and resort to IStream only if MAPI_E_NOT_ENOUGH_MEMORY is returned.

See Also

Subject Properties


PR_NULL

The PR_NULL property represents a null value or setting of a property or reserves array space.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x0000
Property type: | PT_NULL
Property tag: | 0x00000001

Remarks

The PR_NULL property is used to reserve space in arrays of SPropValue structures. It is used in an array of SPropTag structures to tell the method to reserve space in the returned array of SPropValue structures. This allows for computed properties to be filled in an inexpensive way.

For more information, see About Property Types.

See Also

Specialized Usage Properties


PR_OBJECT_TYPE

The PR_OBJECT_TYPE property contains the type of an object.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Address book container, distribution list, folder, messaging user, message, and message store objects
Identifier: | 0x0FFE
Property type: | PT_LONG
Property tag: | 0x0FFE0003

Remarks

The object type contained in the PR_OBJECT_TYPE property corresponds to the primary interface available for an object accessible through the OpenEntry interface. It is usually obtained by consulting the lpulObjType parameter returned by the appropriate OpenEntry method. When the interface is obtained in other ways, call IMAPIProp::GetProps to obtain the value for PR_OBJECT_TYPE.

PR_OBJECT_TYPE can have exactly one of the following values:

MAPI_ABCONT
Address book container object
MAPI_ADDRBOOK
Address book object
MAPI_ATTACH
Message attachment object
MAPI_DISTLIST
Distribution list object
MAPI_FOLDER
Folder object
MAPI_FORMINFO
Form object
MAPI_MAILUSER
Messaging user object
MAPI_MESSAGE
Message object
MAPI_PROFSECT
Profile section object
MAPI_STATUS
Status object
MAPI_STORE
Message store object

For more information on object types, see Objects and Interfaces.

See Also

General Object Properties


PR_OBSOLETED_IPMS

The PR_OBSOLETED_IPMS property contains the identifiers of messages that this message supersedes.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x001F
Property type: | PT_BINARY
Property tag: | 0x001F0102
Corresponding X.400 attribute: | IM_OBSOLETED_IPMS

Remarks

The identifiers contained in the PR_OBSOLETED_IPMS property are standard search keys using the format of the PR_SEARCH_KEY property.

See Also

Conversation Properties, PR_SEARCH_KEY


PR_OFFICE_LOCATION

The PR_OFFICE_LOCATION property contains the recipient's office location.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A19
Property type: | PT_TSTRING
Property tag: | 0x3A19001E (0x3A19001F for Unicode)

Remarks

The PR_OFFICE_LOCATION property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_ORGANIZATIONAL_ID_NUMBER

The PR_ORGANIZATIONAL_ID_NUMBER property contains an identifier for the recipient used within the recipient's organization.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A10
Property type: | PT_TSTRING
Property tag: | 0x3A10001E (0x3A10001F for Unicode)

Remarks

The PR_ORGANIZATIONAL_ID_NUMBER property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

PR_ORGANIZATIONAL_ID_NUMBER is commonly set to an employee number.

See Also

Personal Information Properties


PR_ORIG_MESSAGE_CLASS

The PR_ORIG_MESSAGE_CLASS property contains the class of the original message for use in a report.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x004B
Property type: | PT_TSTRING
Property tag: | 0x004B001E (0x004B001F for Unicode)

Remarks

The PR_ORIG_MESSAGE_CLASS property contains a copy of the PR_MESSAGE_CLASS property of the message for which the report is being generated.

See Also

Message Properties


PR_ORIGIN_CHECK

The PR_ORIGIN_CHECK property contains a binary verification value enabling a delivery report recipient to verify the origin of the original message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0027
Property type: | PT_BINARY
Property tag: | 0x00270102
Corresponding X.400 attribute: | MH_T_ORIGIN_CHECK

Remarks

The PR_ORIGIN_CHECK property provides a means for a third party, such as a message transfer agent (MTA) or a messaging user receiving a delivery report, to verify the submitted message's origin. If present on a received message, this property should be copied onto any delivery report generated in response to the message.

PR_ORIGIN_CHECK replaces several obsolete properties supplied in pre-release versions of MAPI, including PR_MESSAGE_ORIGIN_AUTHENTICATION_CHECK, PR_PROBE_SUBMISSION_AUTHENTICATION_CHECK, and PR_REPORT_ORIGIN_AUTHENTICATION_CHECK.

See Also

Origination Properties, PR_ORIGINATOR_CERTIFICATE


PR_ORIGINAL_AUTHOR_ADDRTYPE

The PR_ORIGINAL_AUTHOR_ADDRTYPE property contains the address type of the author of the first version of a message, that is, the message before being forwarded or replied to.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0079
Property type: | PT_TSTRING
Property tag: | 0x0079001E (0x0079001F for Unicode)

Remarks

The PR_ORIGINAL_AUTHOR_ADDRTYPE property is one of the address properties for the author of a message. At first submission of the message, the client application should set this property to the value of the PR_SENDER_ADDRTYPE property. It is never changed when the message is forwarded or replied to.

The original author properties allow for preservation of information from outside the local messaging domain. When a message arrives from another messaging domain, such as from the Internet, these properties provide a way to ensure that original information is not lost.

For more information on the address properties, see Base Address Properties.

See Also

Original Author Properties, PR_ADDRTYPE


PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS

The PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS property contains the e-mail address of the author of the first version of a message, that is, the message before being forwarded or replied to.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x007A
Property type: | PT_TSTRING
Property tag: | 0x007A001E (0x007A001F for Unicode)

Remarks

The PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS property is one of the address properties for the author of a message. At first submission of the message, the client application should set this property to the value of PR_SENDER_EMAIL_ADDRESS. It is never changed when the message is forwarded or replied to.

The original author properties allow for preservation of information from outside the local messaging domain. When a message arrives from another messaging domain, such as from the Internet, these properties provide a way to ensure that original information is not lost.

For more information on the address properties, see Base Address Properties.

See Also

Original Author Properties, PR_EMAIL_ADDRESS


PR_ORIGINAL_AUTHOR_ENTRYID

The PR_ORIGINAL_AUTHOR_ENTRYID property contains the entry identifier of the author of the first version of a message, that is, the message before being forwarded or replied to.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x004C
Property type: | PT_BINARY
Property tag: | 0x004C0102

Remarks

The PR_ORIGINAL_AUTHOR_ENTRYID property is one of the address properties for the author of a message. At first submission of the message, the client application should set this property to the value of PR_SENDER_ENTRYID. It is never changed when the message is forwarded or replied to.

The original author properties allow for preservation of information from outside the local messaging domain. When a message arrives from another messaging domain, such as from the Internet, these properties provide a way to ensure that original information is not lost.

For more information on the address properties, see Base Address Properties.

See Also

Original Author Properties, PR_ENTRYID


PR_ORIGINAL_AUTHOR_NAME

The PR_ORIGINAL_AUTHOR_NAME property contains the display name of the author of the first version of a message, that is, the message before being forwarded or replied to.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x004D
Property type: | PT_TSTRING
Property tag: | 0x004D001E (0x004D001F for Unicode)
Corresponding X.400 attribute: | MH_T_ORIGINATOR_NAME

Remarks

The PR_ORIGINAL_AUTHOR_NAME property is one of the address properties for the author of a message. At first submission of the message, the client application should set this property to the value of PR_SENDER_NAME. It is never changed when the message is forwarded or replied to.

The original author properties allow for preservation of information from outside the local messaging domain. When a message arrives from another messaging domain, such as from the Internet, these properties provide a way to ensure that original information is not lost.

For more information on the address properties, see Base Address Properties.

See Also

Original Author Properties, PR_DISPLAY_NAME


PR_ORIGINAL_AUTHOR_SEARCH_KEY

The PR_ORIGINAL_AUTHOR_SEARCH_KEY property contains the search key of the author of the first version of a message, that is, the message before being forwarded or replied to.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0056
Property type: | PT_BINARY
Property tag: | 0x00560102

Remarks

The PR_ORIGINAL_AUTHOR_SEARCH_KEY property is one of the address properties for the author of a message. At first submission of the message, the client application should set this property to the value of PR_SENDER_SEARCH_KEY. It is never changed when the message is forwarded or replied to.

The original author properties allow for preservation of information from outside the local messaging domain. When a message arrives from another messaging domain, such as from the Internet, these properties provide a way to ensure that original information is not lost.

For more information on the address properties, see Base Address Properties.

See Also

Original Author Properties, PR_SEARCH_KEY


PR_ORIGINAL_DELIVERY_TIME

The PR_ORIGINAL_DELIVERY_TIME property contains a copy of the original message's delivery date and time in a thread.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Read and nonread report objects
Identifier: | 0x0055
Property type: | PT_SYSTIME
Property tag: | 0x00550040

Remarks

The PR_ORIGINAL_DELIVERY_TIME property is copied from the original PR_MESSAGE_DELIVERY_TIME property in subsequent reply or forward operations and used in read and nonread reports. Delivery reports use the PR_DELIVER_TIME property instead.

See Also

Time Properties


PR_ORIGINAL_DISPLAY_BCC

The PR_ORIGINAL_DISPLAY_BCC property contains the display names of any blind carbon copy (BCC) recipients of the original message.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0072
Property type: | PT_TSTRING
Property tag: | 0x0072001E (0x0072001F for Unicode)

Remarks

The PR_ORIGINAL_DISPLAY_BCC property contains an ASCII list separated by semicolons. It is furnished by MAPI and is copied directly from PR_DISPLAY_BCC when a delivery or nondelivery report or a read or nonread report is generated. PR_ORIGINAL_DISPLAY_BCC may be present on other messages as defined by their message classes.

See Also

Recipient List Properties


PR_ORIGINAL_DISPLAY_CC

The PR_ORIGINAL_DISPLAY_CC property contains the display names of any carbon copy (CC) recipients of the original message.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Report message objects
Identifier: | 0x0073
Property type: | PT_TSTRING
Property tag: | 0x0073001E (0x0073001F for Unicode)

Remarks

The PR_ORIGINAL_DISPLAY_CC property contains an ASCII list separated by semicolons. It is furnished by MAPI and is copied directly from PR_DISPLAY_CC when a delivery or nondelivery report or a read or nonread report is generated. PR_ORIGINAL_DISPLAY_CC may be present on other messages as defined by their message classes.

See Also

Recipient List Properties


PR_ORIGINAL_DISPLAY_NAME

The PR_ORIGINAL_DISPLAY_NAME property contains the original display name for an entry copied from an address book to a personal address book or other writable address book.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A13
Property type: | PT_TSTRING
Property tag: | 0x3A13001E (0x3A13001F for Unicode)

Remarks

The PR_ORIGINAL_DISPLAY_NAME property is one of the properties that contain information about the original source of a copied entry.

For a nonread report, PR_ORIGINAL_DISPLAY_NAME contains a copy of the display name of the original message recipient for which the report is generated. When the original recipient is part of a distribution list, the display name of the distribution list is preserved for the report.

A client application can use PR_ORIGINAL_DISPLAY_NAME to prevent alteration or "spoofing" of entries. An example of spoofing is displaying John Doe as John (What a Guy) Doe.

See Also

Original Messaging User Properties, PR_TRANSMITTABLE_DISPLAY_NAME


PR_ORIGINAL_DISPLAY_TO

The PR_ORIGINAL_DISPLAY_TO property contains the display names of the primary (To) recipients of the original message.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Report message objects
Identifier: | 0x0074
Property type: | PT_TSTRING
Property tag: | 0x0074001E (0x0074001F for Unicode)

Remarks

The PR_ORIGINAL_DISPLAY_TO property contains an ASCII list separated by semicolons. It is furnished by MAPI and is copied directly from PR_DISPLAY_TO when a delivery or nondelivery report or a read or nonread report is generated. PR_ORIGINAL_DISPLAY_TO may be present on other messages as defined by their message classes.

See Also

Recipient List Properties


PR_ORIGINAL_EITS

The PR_ORIGINAL_EITS property contains a copy of the original encoded information types (EITs) for message text.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0021
Property type: | PT_BINARY
Property tag: | 0x00210102
Corresponding X.400 attribute: | MH_T_ORIGINAL_EITS

See Also

Conversion Properties


PR_ORIGINAL_ENTRYID

The PR_ORIGINAL_ENTRYID property contains the original entry identifier for an entry copied from an address book to a personal address book or other writeable address book.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A12
Property type: | PT_BINARY
Property tag: | 0x3A120102

Remarks

The PR_ORIGINAL_ENTRYID property is one of the properties that contain information about the original source of a copied entry.

For a nonread report, PR_ORIGINAL_ENTRYID contains a copy of the entry identifier of the original message recipient for which the report is generated. When the original recipient is part of a distribution list, the entry identifier of the distribution list is preserved for the report.

See Also

Original Messaging User Properties


PR_ORIGINAL_SEARCH_KEY

The PR_ORIGINAL_SEARCH_KEY property contains the original search key for an entry copied from an address book to a personal address book or other writeable address book.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A14
Property type: | PT_BINARY
Property tag: | 0x3A140102

Remarks

The PR_ORIGINAL_SEARCH_KEY property is one of the properties that contain information about the original source of a copied entry.

For a nonread report, PR_ORIGINAL_SEARCH_KEY contains a copy of the search key of the original message recipient for which the report is generated. When the original recipient is part of a distribution list, the search key of the distribution list is preserved for the report.

See Also

Original Messaging User Properties


PR_ORIGINAL_SENDER_ADDRTYPE

The PR_ORIGINAL_SENDER_ADDRTYPE property contains the address type of the sender of the first version of a message, that is, the message before being forwarded or replied to.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0066
Property type: | PT_TSTRING
Property tag: | 0x0066001E (0x0066001F for Unicode)

Remarks

The PR_ORIGINAL_SENDER_ADDRTYPE property is one of the address properties for the original sender of a message. At first submission of the message, the client application should set this property to the value of PR_SENDER_ADDRTYPE. It is never changed when the message is forwarded or replied to.

For more information on the address properties, see Base Address Properties.

See Also

Original Sender Properties


PR_ORIGINAL_SENDER_EMAIL_ADDRESS

The PR_ORIGINAL_SENDER_EMAIL_ADDRESS property contains the e-mail address of the sender of the first version of a message, that is, the message before being forwarded or replied to.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0067
Property type: | PT_TSTRING
Property tag: | 0x0067001E (0x0067001F for Unicode)

Remarks

The PR_ORIGINAL_SENDER_EMAIL_ADDRESS property is one of the address properties for the original sender of a message. At first submission of the message, the client application should set this property to the value of PR_SENDER_EMAIL_ADDRESS. It is never changed when the message is forwarded or replied to.

For more information on the address properties, see Base Address Properties.

See Also

Original Sender Properties


PR_ORIGINAL_SENDER_ENTRYID

The PR_ORIGINAL_SENDER_ENTRYID property contains the entry identifier of the sender of the first version of a message, that is, the message before being forwarded or replied to.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x005B
Property type: | PT_BINARY
Property tag: | 0x005B0102

Remarks

The PR_ORIGINAL_SENDER_ENTRYID property is one of the address properties for the original sender of a message. At first submission of the message, a client application should set this property to the value of the PR_SENDER_ENTRYID property. It is never changed when the message is forwarded or replied to.

For more information on the address properties, see Base Address Properties.

See Also

Original Sender Properties


PR_ORIGINAL_SENDER_NAME

The PR_ORIGINAL_SENDER_NAME property contains the display name of the sender of the first version of a message, that is, the message before being forwarded or replied to.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x005A
Property type: | PT_TSTRING
Property tag: | 0x005A001E (0x005A001F for Unicode)
Corresponding X.400 attribute: | MH_T_ORIGINATOR_NAME

Remarks

The PR_ORIGINAL_SENDER_NAME property is one of the address properties for the original sender of a message. At first submission of the message, a client application should set this property to the value of the PR_SENDER_NAME property. It is never changed when the message is forwarded or replied to.

For more information on the address properties, see Base Address Properties.

See Also

Original Sender Properties


PR_ORIGINAL_SENDER_SEARCH_KEY

The PR_ORIGINAL_SENDER_SEARCH_KEY property contains the search key for the sender of the first version of a message, that is, the message before being forwarded or replied to.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x005C
Property type: | PT_BINARY
Property tag: | 0x005C0102

Remarks

The PR_ORIGINAL_SENDER_SEARCH_KEY property is one of the address properties for the original sender of a message. At first submission of the message, the client application should set this property to the value of the PR_SENDER_SEARCH_KEY property. It is never changed when the message is forwarded or replied to.

For more information on the address properties, see Base Address Properties.

See Also

Original Sender Properties


PR_ORIGINAL_SENSITIVITY

The PR_ORIGINAL_SENSITIVITY property contains the sensitivity value assigned by the sender of the first version of a message that is, the message before being forwarded or replied to.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x002E
Property type: | PT_LONG
Property tag: | 0x002E0003

Remarks

A client application should set the PR_ORIGINAL_SENSITIVITY property to the same value as the PR_SENSITIVITY property when the message is first submitted. It should never be changed subsequently.

PR_ORIGINAL_SENSITIVITY is used by the transport provider to protect the sensitivity on copied entries. It enables it, for example, to block modification of the original message text in a forward of or reply to a message that was originally marked SENSITIVITY_PRIVATE.

See Also

Criticality Properties


PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE

The PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE property contains the address type of the messaging user on whose behalf the original message was sent.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0068
Property type: | PT_TSTRING
Property tag: | 0x0068001E (0x0068001F for Unicode)

Remarks

The PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE property is one of the address properties for the original represented sender of a message. It is used in a conversation thread.

A client application sending a message on behalf of another client should set this property to the value of the PR_SENT_REPRESENTING_ADDRTYPE property at the first submission of the message. Once set, it should never be changed.

For more information on the address properties, see Base Address Properties.

See Also

Original Represented Sender Properties


PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS

The PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS property contains the e-mail address of the messaging user on whose behalf the original message was sent.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0069
Property type: | PT_TSTRING
Property tag: | 0x0069001E (0x0069001F for Unicode)

Remarks

The PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS property is one of the address properties for the original represented sender of a message. It is used in a conversation thread.

A client application sending a message on behalf of another client should set this property to the value of the PR_SENT_REPRESENTING_EMAIL_ADDRESS property at the first submission of the message. Once set, it should never be changed.

For more information on the address properties, see Base Address Properties.

See Also

Original Represented Sender Properties


PR_ORIGINAL_SENT_REPRESENTING_ENTRYID

The PR_ORIGINAL_SENT_REPRESENTING_ENTRYID property contains the entry identifier of the messaging user on whose behalf the original message was sent.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x005E
Property type: | PT_BINARY
Property tag: | 0x005E0102

Remarks

The PR_ORIGINAL_SENT_REPRESENTING_ENTRYID property is one of the address properties for the original represented sender of a message. It is used in a conversation thread.

A client application sending a message on behalf of another client should set this property to the value of the PR_SENT_REPRESENTING_ENTRYID property at the first submission of the message. Once set, it should never be changed.

For more information on the address properties, see Base Address Properties.

See Also

Original Represented Sender Properties


PR_ORIGINAL_SENT_REPRESENTING_NAME

The PR_ORIGINAL_SENT_REPRESENTING_NAME property contains the display name of the messaging user on whose behalf the original message was sent.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x005D
Property type: | PT_TSTRING
Property tag: | 0x005D001E (0x005D001F for Unicode)

Remarks

The PR_ORIGINAL_SENT_REPRESENTING_NAME property is one of the address properties for the original represented sender of a message. It is used in a conversation thread.

A client application sending a message on behalf of another client should set this property to the value of the PR_SENT_REPRESENTING_NAME property at the first submission of the message. Once set, it should never be changed.

For more information on the address properties, see Base Address Properties.

See Also

Original Represented Sender Properties


PR_ORIGINAL_SENT_REPRESENTING_SEARCH_KEY

The PR_ORIGINAL_SENT_REPRESENTING_SEARCH_KEY property contains the search key of the messaging user on whose behalf the original message was sent.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x005F
Property type: | PT_BINARY
Property tag: | 0x005F0102

Remarks

The PR_ORIGINAL_SENT_REPRESENTING_SEARCH_KEY property is one of the address properties for the original represented sender of a message. It is used in a conversation thread.

A client application sending a message on behalf of another client should set this property to the value of the PR_SENT_REPRESENTING_SEARCH_KEY property at the first submission of the message. Once set, it should never be changed.

For more information on the address properties, see Base Address Properties.

See Also

Original Represented Sender Properties


PR_ORIGINAL_SUBJECT

The PR_ORIGINAL_SUBJECT property contains the subject of an original message for use in a report about the message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0049
Property type: | PT_TSTRING
Property tag: | 0x0049001E (0x0049001F for Unicode)
Corresponding X.400 attribute: | IM_SUBJECT

Remarks

The PR_ORIGINAL_SUBJECT property is originally set to the same value as the PR_SUBJECT property.

The subject properties are typically small strings of fewer than 256 characters, and a message store provider is not obligated to support the OLE IStream interface on them. The client should always attempt access through the IMAPIProp interface first, and resort to IStream only if MAPI_E_NOT_ENOUGH_MEMORY is returned.


PR_ORIGINAL_SUBMIT_TIME

The PR_ORIGINAL_SUBMIT_TIME property contains the original submission date and time of the message in the report.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Report message objects
Identifier: | 0x004E
Property type: | PT_SYSTIME
Property tag: | 0x004E0040

Remarks

At first submission of a message, a client application should set the PR_ORIGINAL_SUBMIT_TIME property to the value of the PR_CLIENT_SUBMIT_TIME property. It is not changed when the message is forwarded. This is used in reports only.

See Also

Time Properties


PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE

The PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE property contains the address type of the originally intended recipient of an autoforwarded message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x007B
Property type: | PT_TSTRING
Property tag: | 0x007B001E (0x007B001F for Unicode)
Corresponding X.400 attribute: | IM_IPM_INTENDED_RECIPIENT

Remarks

The PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE property is one of the address properties for the originally intended message recipient. It must be set by the automatic agent that has forwarded the message.

For more information on the address properties, see Base Address Properties.

See Also

Originally Intended Recipient Properties, PR_ADDRTYPE


PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS

The PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS property contains the e-mail address of the originally intended recipient of an autoforwarded message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x007C
Property type: | PT_TSTRING
Property tag: | 0x007C001E (0x007C001F for Unicode)

Remarks

The PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS property is one of the address properties for the originally intended message recipient. It must be set by the automatic agent that has forwarded the message.

For more information on the address properties, see Base Address Properties.

PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS corresponds to the X.400 report per-recipient attribute.

See Also

Originally Intended Recipient Properties, PR_EMAIL_ADDRESS


PR_ORIGINALLY_INTENDED_RECIP_ENTRYID

The PR_ORIGINALLY_INTENDED_RECIP_ENTRYID property contains the entry identifier of the originally intended recipient of an autoforwarded message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x1012
Property type: | PT_BINARY
Property tag: | 0x10120102

Remarks

The PR_ORIGINALLY_INTENDED_RECIP_ENTRYID property is one of the address properties for the originally intended message recipient. It must be set by the automatic agent that has forwarded the message.

For more information on the address properties, see Base Address Properties.

PR_ORIGINALLY_INTENDED_RECIP_ENTRYID corresponds to the X.400 report per-recipient attribute.

See Also

Originally Intended Recipient Properties, PR_ENTRYID


PR_ORIGINALLY_INTENDED_RECIPIENT_NAME

The PR_ORIGINALLY_INTENDED_RECIPIENT_NAME property contains the encoded name of the originally intended recipient of an autoforwarded message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0020
Property type: | PT_BINARY
Property tag: | 0x00200102
Corresponding X.400 attribute: | MH_T_ORIGINALLY_INTENDED_RECIP

Remarks

The PR_ORIGINALLY_INTENDED_RECIPIENT_NAME property must be set by the automatic agent that has forwarded the message.

This property is not one of the address properties.

See Also

Originally Intended Recipient Properties


PR_ORIGINATING_MTA_CERTIFICATE

The PR_ORIGINATING_MTA_CERTIFICATE property contains an identifier for the message transfer agent (MTA) that originated the message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0E25
Property type: | PT_BINARY
Property tag: | 0x0E250102

Remarks

The PR_ORIGINATING_MTA_CERTIFICATE property, if set, is available on sent messages in the Sent Items folder.

PR_ORIGINATING_MTA_CERTIFICATE corresponds to the X.400 report per-message attribute.

See Also

Origination Properties, PR_REPORTING_MTA_CERTIFICATE


PR_ORIGINATOR_AND_DL_EXPANSION_HISTORY

The PR_ORIGINATOR_AND_DL_EXPANSION_HISTORY property contains information about a message originator and a distribution list expansion history.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x1002
Property type: | PT_BINARY
Property tag: | 0x10020102
Corresponding X.400 attribute: | MH_T_ORIG_AND_EXPANSION_HISTORY

Remarks

The PR_ORIGINATOR_AND_DL_EXPANSION_HISTORY property is used in report generation.

See Also

Origination Properties


PR_ORIGINATOR_CERTIFICATE

The PR_ORIGINATOR_CERTIFICATE property contains an ASN.1 certificate for the message originator.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0022
Property type: | PT_BINARY
Property tag: | 0x00220102
Corresponding X.400 attribute: | MH_T_ORIGINATOR_CERTIFICATE

Remarks

The PR_ORIGINATOR_CERTIFICATE property is a copy of the originator's PR_USER_CERTIFICATE property.

See Also

Certificate Properties


PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED

The PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED property contains TRUE if a message sender requests a delivery report for a particular recipient from the messaging system before the message is placed in the message store.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects, message objects
Identifier: | 0x0023
Property type: | PT_BOOLEAN
Property tag: | 0x0023000B
Corresponding X.400 attribute: | MH_T_ORIGINATOR_REPORT_REQUEST

Remarks

The PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED property is used to direct the messaging system in handling delivered messages. In this case, the message must also furnish the PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED property set to FALSE.

Setting PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED on a message is a way to request delivery status reports for all recipients.

See Also

Origination Properties


PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED

The PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED property contains TRUE if a message sender requests a nondelivery report for a particular recipient.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects
Identifier: | 0x0C08
Property type: | PT_BOOLEAN
Property tag: | 0x0C08000B
Corresponding X.400 attribute: | MH_T_ORIGINATOR_REPORT_REQUEST

Remarks

The PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED property is used to direct the messaging system in handling undelivered messages. In this case, the message must also furnish the PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED property set to FALSE.

See Also

Origination Properties


PR_ORIGINATOR_REQUESTED_ALTERNATE_RECIPIENT

The PR_ORIGINATOR_REQUESTED_ALTERNATE_RECIPIENT property contains an entry identifier for an alternate recipient designated by the sender.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects
Identifier: | 0x0C09
Property type: | PT_BINARY
Property tag: | 0x0C090102

Remarks

The PR_ORIGINATOR_REQUESTED_ALTERNATE_RECIPIENT property is used in autoforwarded messages. If autoforwarding is not permitted or if no alternate recipient has been designated, a nondelivery report should be generated.

See Also

Alternate Recipient Properties


PR_ORIGINATOR_RETURN_ADDRESS

The PR_ORIGINATOR_RETURN_ADDRESS property contains the binary-encoded return address of the message originator.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0024
Property type: | PT_BINARY
Property tag: | 0x00240102
Corresponding X.400 attribute: | MH_T_ORIGINATOR_RETURN_ADDRESS

See Also

Origination Properties


PR_OTHER_TELEPHONE_NUMBER

The PR_OTHER_TELEPHONE_NUMBER property contains an alternate telephone number for the recipient.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A1F
Property type: | PT_TSTRING
Property tag: | 0x3A1F001E (0x3A1F001F for Unicode)

Remarks

The PR_OTHER_TELEPHONE_NUMBER property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on these properties, see IMailUser::IMAPIProp.

PR_OTHER_TELEPHONE_NUMBER is used for a telephone number other than at the recipient's place of business, home, or office.

See Also

Personal Information Properties


PR_OWN_STORE_ENTRYID

The PR_OWN_STORE_ENTRYID property contains the entry identifier of a transport's tightly coupled message store.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Status objects
May be a column in: | Status tables
Identifier: | 0x3E06
Property type: | PT_BINARY
Property tag: | 0x3E060102

Remarks

The PR_OWN_STORE_ENTRYID property specifies the entry identifier for the tightly coupled store, if one exists. For example, a transport provider can specify the private folder store entry identifier so that the MAPI spooler can connect the transport provider to the store.

See Also

Provider Properties, PR_STORE_ENTRYID


PR_OWNER_APPT_ID

The PR_OWNER_APPT_ID property contains an identifier for an appointment in the owner's schedule.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects used for scheduling
Identifier: | 0x0062
Property type: | PT_LONG
Property tag: | 0x00620003

Remarks

The PR_OWNER_APPT_ID property is used in meeting requests. It does not represent an entry identifier, but a long integer that uniquely identifies the appointment within the sender's schedule.

See Also

Schedule Properties, PR_ORIGINAL_AUTHOR_SEARCH_KEY


PR_PAGER_TELEPHONE_NUMBER

The PR_PAGER_TELEPHONE_NUMBER property contains the recipient's pager telephone number.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A21
Property type: | PT_TSTRING
Property tag: | 0x3A21001E (0x3A21001F for Unicode)

Remarks

The PR_PAGER_TELEPHONE_NUMBER property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on these properties, see IMailUser::IMAPIProp.

MAPI also supports the PR_BEEPER_TELEPHONE_NUMBER property that is synonymous with PR_PAGER_TELEPHONE_NUMBER.

See Also

Personal Information Properties


PR_PARENT_DISPLAY

The PR_PARENT_DISPLAY property contains the display name of the folder in which a message was found during a search.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | Contents tables for search-results folders
Identifier: | 0x0E05
Property type: | PT_TSTRING
Property tag: | 0x0E05001E (0x0E05001F for Unicode)

Remarks

The PR_PARENT_DISPLAY property is not a property of any object. It can only appear in the contents table of a search-results folder.

The PR_PARENT_DISPLAY, PR_PARENT_ENTRYID, and PR_PARENT_KEY properties are not related to each other. They belong to entirely different contexts.

See Also

Table Row Properties


PR_PARENT_ENTRYID

The PR_PARENT_ENTRYID property contains the entry identifier of the folder containing a folder or message.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Folder and message objects
May be a column in: | Folder contents tables
Identifier: | 0x0E09
Property type: | PT_BINARY
Property tag: | 0x0E090102

Remarks

The PR_PARENT_ENTRYID property is computed by message stores for all folders and messages.

For a message store root folder, PR_PARENT_ENTRYID contains the folder's own entry identifier.

The PR_PARENT_DISPLAY, PR_PARENT_ENTRYID, and PR_PARENT_KEY properties are not related to each other. They belong to entirely different contexts.

See Also

Folder Properties, PR_FOLDER_TYPE


PR_PARENT_KEY

The PR_PARENT_KEY property was originally meant to contain a value used in correlating conversation threads.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x0025
Property type: | PT_BINARY
Property tag: | 0x00250102
Corresponding X.400 attribute: | IM_REPLIED_TO_IPM

Remarks

Do not use this property. It is not supported in MAPI 1.0.

See Also

Unused Properties


PR_PHYSICAL_DELIVERY_BUREAU_FAX_DELIVERY

The PR_PHYSICAL_DELIVERY_BUREAU_FAX_DELIVERY property contains TRUE if the messaging system should use a fax bureau for physical delivery of this message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0C0A
Property type: | PT_BOOLEAN
Property tag: | 0x0C0A000B
Corresponding X.400 attribute: | MH_T_BUREAU_FAX_DELIVERY

See Also

Physical Delivery Properties


PR_PHYSICAL_DELIVERY_MODE

The PR_PHYSICAL_DELIVERY_MODE property contains a bitmask of flags defining the physical delivery mode (for example, special delivery) for a message designated for a specific recipient.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects
Identifier: | 0x0C0B
Property type: | PT_LONG
Property tag: | 0x0C0B0003
Corresponding X.400 attribute: | MH_T_POSTAL_MODE

See Also

Physical Delivery Properties


PR_PHYSICAL_DELIVERY_REPORT_REQUEST

The PR_PHYSICAL_DELIVERY_REPORT_REQUEST property contains the mode of a report to be delivered to a particular message recipient upon completion of physical message delivery or delivery by the message handling system.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects
Identifier: | 0x0C0C
Property type: | PT_LONG
Property tag: | 0x0C0C0003
Corresponding X.400 attribute: | MH_T_POSTAL_REPORT

See Also

Physical Delivery Properties


PR_PHYSICAL_FORWARDING_ADDRESS

The PR_PHYSICAL_FORWARDING_ADDRESS property contains the physical forwarding address of a message recipient and is used only with message reports.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects
Identifier: | 0x0C0D
Property type: | PT_BINARY
Property tag: | 0x0C0D0102
Corresponding X.400 attribute: | MH_T_FORWARDING_ADDRESS

See Also

Physical Delivery Properties


PR_PHYSICAL_FORWARDING_ADDRESS_REQUESTED

The PR_PHYSICAL_FORWARDING_ADDRESS_REQUESTED property contains TRUE if a message sender requests the message transfer agent to attach a physical forwarding address for a message recipient.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects
Identifier: | 0x0C0E
Property type: | PT_BOOLEAN
Property tag: | 0x0C0E000B
Corresponding X.400 attribute: | MH_T_FORWARDING_ADR_REQUESTED

See Also

Physical Delivery Properties


PR_PHYSICAL_FORWARDING_PROHIBITED

The PR_PHYSICAL_FORWARDING_PROHIBITED property contains TRUE if a message sender prohibits physical message forwarding for a specific recipient.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects
Identifier: | 0x0C0F
Property type: | PT_BOOLEAN
Property tag: | 0x0C0F000B
Corresponding X.400 attribute: | MH_T_FORWARDING_PROHIBITED

See Also

Physical Delivery Properties


PR_PHYSICAL_RENDITION_ATTRIBUTES

The PR_PHYSICAL_RENDITION_ATTRIBUTES property contains an ASN.1 object identifier used for rendering message attachments.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Attachment subobjects
Identifier: | 0x0C10
Property type: | PT_BINARY
Property tag: | 0x0C100102
Corresponding X.400 attribute: | MH_T_RENDITION_ATTRIBUTES

See Also

Attachment Properties


PR_POST_OFFICE_BOX

The PR_POST_OFFICE_BOX property contains the number or identifier of the recipient's post office box.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A2B
Property type: | PT_TSTRING
Property tag: | 0x3A2B001E (0x3A2B001F for Unicode)

Remarks

The PR_POST_OFFICE_BOX property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_POSTAL_ADDRESS

The PR_POSTAL_ADDRESS property contains the recipient's postal address.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A15
Property type: | PT_TSTRING
Property tag: | 0x3A15001E (0x3A15001F for Unicode)

Remarks

The PR_POSTAL_ADDRESS property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_POSTAL_CODE

The PR_POSTAL_CODE property contains the postal code for the recipient's postal address.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A2A
Property type: | PT_TSTRING
Property tag: | 0x3A2A001E (0x3A2A001F for Unicode)

Remarks

The PR_POSTAL_CODE property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

The postal code is specific to the recipient's country. In the United States of America, this property contains the ZIP code.

See Also

Personal Information Properties


PR_PREPROCESS

The PR_PREPROCESS property contains TRUE if the message requires preprocessing.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x0E22
Property type: | PT_BOOLEAN
Property tag: | 0x0E22000B

Remarks

Do not use this property. It is reserved for use by MAPI.

See Also

Reserved Properties, PR_SUBMIT_FLAGS


PR_PRIMARY_CAPABILITY

Obsolete address book property.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3904
Property type: | PT_BINARY
Property tag: | 0x39040102

Remarks

Do not use this property.

See Also

Unused Properties


PR_PRIMARY_FAX_NUMBER

The PR_PRIMARY_FAX_NUMBER property contains the telephone number of the recipient's primary fax machine.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A23
Property type: | PT_TSTRING
Property tag: | 0x3A23001E (0x3A23001F for Unicode)

Remarks

The PR_PRIMARY_FAX_NUMBER property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_PRIMARY_TELEPHONE_NUMBER

The PR_PRIMARY_TELEPHONE_NUMBER property contains the recipient's primary telephone number.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A1A
Property type: | PT_TSTRING
Property tag: | 0x3A1A001E (0x3A1A001F for Unicode)
Corresponding X.400 attribute: | IM_TELEPHONE_NUMBER

Remarks

The PR_PRIMARY_TELEPHONE_NUMBER property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_PRIORITY

The PR_PRIORITY property contains the relative priority of a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0026
Property type: | PT_LONG
Property tag: | 0x00260003
Corresponding X.400 attribute: | MH_T_PRIORITY

Remarks

The PR_PRIORITY and PR_IMPORTANCE properties should not be confused. Importance indicates a value to users, while priority indicates the order or speed at which the message should be sent by the messaging system software. Higher priority usually indicates a higher cost. Higher importance usually is associated with a different display by the user interface.

The priority of a report message should be the same as the priority of the original message being reported.

PR_PRIORITY can have exactly one of the following values:

PRIO_NONURGENT
The message is not urgent.
PRIO_NORMAL
The message has normal priority.
PRIO_URGENT
The message is urgent.

See Also

Criticality Properties


PR_PROFILE_NAME

The PR_PROFILE_NAME property contains the name of the profile.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Profile section objects
Identifier: | 0x3D12
Property type: | PT_TSTRING
Property tag: | 0x3D12001E (0x3D12001F for Unicode)

Remarks

The PR_PROFILE_NAME property is computed by service providers. A provider's implementation of the ServiceEntry function can use the PR_PROFILE_NAME property to discover the profile name.

Client applications can use PR_PROFILE_NAME as a convenient alternative to obtaining the profile name by examining the PR_DISPLAY_NAME property in the MAPI subsystem's status table row.

PR_PROFILE_NAME may not be unique across time, for example where a profile is deleted and later recreated with the same name. MAPI furnishes a totally unique PR_SEARCH_KEY property in a hard-coded profile section called MUID_PROFILE_INSTANCE.


PR_PROOF_OF_DELIVERY

The PR_PROOF_OF_DELIVERY property contains an ASN.1 proof of delivery value.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects
Identifier: | 0x0C11
Property type: | PT_BINARY
Property tag: | 0x0C110102
Corresponding X.400 attribute: | MH_T_PROOF_OF_DELIVERY

See Also

Proof of Progress Properties


PR_PROOF_OF_DELIVERY_REQUESTED

The PR_PROOF_OF_DELIVERY_REQUESTED property contains TRUE if a message sender requests proof of delivery for a particular recipient.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects
Identifier: | 0x0C12
Property type: | PT_BOOLEAN
Property tag: | 0x0C12000B
Corresponding X.400 attribute: | MH_T_PROOF_OF_DELIV_REQUESTED

See Also

Proof of Progress Properties


PR_PROOF_OF_SUBMISSION

The PR_PROOF_OF_SUBMISSION property contains an ASN.1 proof of submission value.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0E26
Property type: | PT_BINARY
Property tag: | 0x0E260102

Remarks

The PR_PROOF_OF_SUBMISSION property corresponds to an X.400 submission envelope per-message attribute.

See Also

Proof of Progress Properties


PR_PROOF_OF_SUBMISSION_REQUESTED

The PR_PROOF_OF_SUBMISSION_REQUESTED property contains TRUE if a message sender requests proof that the message transfer system has submitted a message for delivery to the originally intended recipient.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0028
Property type: | PT_BOOLEAN
Property tag: | 0x0028000B
Corresponding X.400 attribute: | MH_T_PROOF_OF_SUBMSN_REQUESTED

See Also

Proof of Progress Properties


PR_PROVIDER_DISPLAY

The PR_PROVIDER_DISPLAY property contains the vendor-defined display name for a service provider.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Profile section objects
Identifier: | 0x3006
Property type: | PT_TSTRING
Property tag: | 0x3006001E (0x3006001F for Unicode)

Remarks

The PR_PROVIDER_DISPLAY and PR_PROVIDER_DLL_NAME properties are defined only on profile sections belonging to service providers. They must be present in MAPISVC.INF.

See Also

Provider Properties


PR_PROVIDER_DLL_NAME

The PR_PROVIDER_DLL_NAME property contains the base filename of the MAPI service provider DLL.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Profile section objects
Identifier: | 0x300A
Property type: | PT_TSTRING
Property tag: | 0x300A001E (0x300A001F for Unicode)

Remarks

MAPI uses a DLL file naming convention. The base filename contains up to six characters that uniquely identify the DLL. MAPI appends the string 32 to the base DLL name to identify the version that runs on 32-bit platforms. For example, when the name MAPI.DLL is specified, MAPI constructs the name MAPI32.DLL to represent the corresponding 32-bit version of the DLL.

The PR_PROVIDER_DLL_NAME property should specify the base name. MAPI appends the string 32 as appropriate. Including the string 32 as part of the PR_PROVIDER_DLL_NAME property results in an error.

See Also

Provider Properties, PR_SERVICE_DLL_NAME


PR_PROVIDER_ORDINAL

The PR_PROVIDER_ORDINAL property contains the zero-based index of a service provider's position in the provider table.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Provider table objects
Identifier: | 0x300D
Property type: | PT_LONG
Property tag: | 0x300D0003

Remarks

The PR_PROVIDER_ORDINAL property is computed by MAPI.

Obtain the provider table by calling the IMsgServiceAdmin::GetProviderTable method. Sort the provider table on the PR_PROVIDER_ORDINAL column to display the transport order.

See Also

Provider Properties


PR_PROVIDER_SUBMIT_TIME

The PR_PROVIDER_SUBMIT_TIME property contains the date and time a transport provider passed a message to its underlying messaging system.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0048
Property type: | PT_SYSTIME
Property tag: | 0x00480040

Remarks

The PR_PROVIDER_SUBMIT_TIME property is set by the outgoing transport provider at the time a message is sent.

PR_PROVIDER_SUBMIT_TIME corresponds to an X.400 submission envelope per-message attribute.

See Also

Time Properties


PR_PROVIDER_UID

The PR_PROVIDER_UID property contains a MAPIUID structure of the service provider that is handling a message.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Provider table objects
Identifier: | 0x300C
Property type: | PT_BINARY
Property tag: | 0x300C0102

Remarks

The PR_PROVIDER_UID property is computed by all service providers. It contains a MAPIUID structure associated with, and usually hard-coded by, the provider. It is typically used by a client application that is interested in only the address book containers supplied by a particular provider.

PR_PROVIDER_UID appears only as a column entry in the provider table.

See Also

Provider Properties


PR_RADIO_TELEPHONE_NUMBER

The PR_RADIO_TELEPHONE_NUMBER property contains the recipient's radio telephone number.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A1D
Property type: | PT_TSTRING
Property tag: | 0x3A1D001E (0x3A1D001F for Unicode)

Remarks

The PR_RADIO_TELEPHONE_NUMBER property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_RCVD_REPRESENTING_ADDRTYPE

The PR_RCVD_REPRESENTING_ADDRTYPE property contains the address type for the messaging user represented by the user actually receiving the message.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0077
Property type: | PT_TSTRING
Property tag: | 0x0077001E (0x0077001F for Unicode)

Remarks

The PR_RCVD_REPRESENTING_ADDRTYPE property is one of the address properties for the messaging user being represented by the receiving user. It must be set by the incoming transport provider, which is also responsible for authorization or verification of the delegate. If no messaging user is being represented, PR_RCVD_REPRESENTING_ADDRTYPE should be set to the address type contained in the PR_RECEIVED_BY_ADDRTYPE property.

A client application replying to a message received on behalf of another client should copy PR_RCVD_REPRESENTING_ADDRTYPE from the received message into the PR_SENT_REPRESENTING_ADDRTYPE property for the reply.

For more information on the address properties, see Base Address Properties.

See Also

Represented Recipient Properties, PR_ADDRTYPE


PR_RCVD_REPRESENTING_EMAIL_ADDRESS

The PR_RCVD_REPRESENTING_EMAIL_ADDRESS property contains the e-mail address for the messaging user represented by the receiving user.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0078
Property type: | PT_TSTRING
Property tag: | 0x0078001E (0x0078001F for Unicode)

Remarks

The PR_RCVD_REPRESENTING_EMAIL_ADDRESS property is one of the address properties for the messaging user being represented by the receiving user. It must be set by the incoming transport provider, which is also responsible for authorization or verification of the delegate. If no messaging user is being represented, PR_RCVD_REPRESENTING_EMAIL_ADDRESS should be set to the e-mail address contained in the PR_RECEIVED_BY_EMAIL_ADDRESS property.

A client application replying to a message received on behalf of another client should copy PR_RCVD_REPRESENTING_EMAIL_ADDRESS from the received message into the PR_SENT_REPRESENTING_EMAIL_ADDRESS property for the reply.

For more information on the address properties, see Base Address Properties.

See Also

Represented Recipient Properties, PR_EMAIL_ADDRESS


PR_RCVD_REPRESENTING_ENTRYID

The PR_RCVD_REPRESENTING_ENTRYID property contains the entry identifier for the messaging user represented by the receiving user.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0043
Property type: | PT_BINARY
Property tag: | 0x00430102

Remarks

The PR_RCVD_REPRESENTING_ENTRYID property is one of the address properties for the messaging user being represented by the receiving user. It must be set by the incoming transport provider, which is also responsible for authorization or verification of the delegate. If no messaging user is being represented, PR_RCVD_REPRESENTING_ENTRYID should be set to the entry identifier contained in the PR_RECEIVED_BY_ENTRYID property.

A client application replying to a message received on behalf of another client should copy PR_RCVD_REPRESENTING_ENTRYID from the received message into the PR_SENT_REPRESENTING_ENTRYID property for the reply.

For more information on the address properties, see Base Address Properties.

See Also

Represented Recipient Properties, PR_ENTRYID


PR_RCVD_REPRESENTING_NAME

The PR_RCVD_REPRESENTING_NAME property contains the display name for the messaging user represented by the receiving user.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0044
Property type: | PT_TSTRING
Property tag: | 0x0044001E (0x0044001F for Unicode)

Remarks

The PR_RCVD_REPRESENTING_NAME property is one of the address properties for the messaging user being represented by the receiving user. It must be set by the incoming transport provider, which is also responsible for authorization or verification of the delegate. If no messaging user is being represented, PR_RCVD_REPRESENTING_NAME should be set to the display name contained in the PR_RECEIVED_BY_NAME property.

A client application replying to a message received on behalf of another client should copy PR_RCVD_REPRESENTING_NAME from the received message into the PR_SENT_REPRESENTING_NAME property for the reply.

For more information on the address properties, see Base Address Properties.

See Also

Represented Recipient Properties, PR_DISPLAY_NAME


PR_RCVD_REPRESENTING_SEARCH_KEY

The PR_RCVD_REPRESENTING_SEARCH_KEY property contains the search key for the messaging user represented by the receiving user.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0052
Property type: | PT_BINARY
Property tag: | 0x00520102

Remarks

The PR_RCVD_REPRESENTING_SEARCH_KEY is one of the address properties for the messaging user being represented by the receiving user. It must be set by the incoming transport provider, which is also responsible for authorization or verification of the delegate. If no messaging user is being represented, PR_RCVD_REPRESENTING_SEARCH_KEY should be set to the search key contained in the PR_RECEIVED_BY_SEARCH_KEY property.

A client application replying to a message received on behalf of another client should copy PR_RCVD_REPRESENTING_SEARCH_KEY from the received message into the PR_SENT_REPRESENTING_SEARCH_KEY property for the reply.

For more information on the address properties, see Base Address Properties.

See Also

Represented Recipient Properties, PR_SEARCH_KEY


PR_READ_RECEIPT_ENTRYID

The PR_READ_RECEIPT_ENTRYID property contains an entry identifier for the messaging user to which the messaging system should direct a read report for this message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0046
Property type: | PT_BINARY
Property tag: | 0x00460102

Remarks

The PR_READ_RECEIPT_ENTRYID property is ignored unless the PR_READ_RECEIPT_REQUESTED property is set to TRUE.

If a client application wants to receive read reports itself, it can leave PR_READ_RECEIPT_ENTRYID unset or set it to the entry identifier contained in the PR_SENDER_ENTRYID property at message submission time.

See Also

Report Recipient Properties


PR_READ_RECEIPT_REQUESTED

The PR_READ_RECEIPT_REQUESTED property contains TRUE if a message sender wants the messaging system to generate a read report when the recipient has read a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects, message objects
Identifier: | 0x0029
Property type: | PT_BOOLEAN
Property tag: | 0x0029000B
Corresponding X.400 attribute: | IM_NOTIFICATION_REQUEST

Remarks

The PR_READ_RECEIPT_REQUESTED property must be set to TRUE to validate the values in the PR_READ_RECEIPT_ENTRYID and PR_READ_RECEIPT_SEARCH_KEY properties.

If a message with PR_READ_RECEIPT_REQUESTED set is deleted or expires before the messaging system can generate a read report, a nonread report is generated.

See Also

Report Properties


PR_READ_RECEIPT_SEARCH_KEY

The PR_READ_RECEIPT_SEARCH_KEY property contains a search key for the messaging user to which the messaging system should direct a read report for a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0053
Property type: | PT_BINARY
Property tag: | 0x00530102

Remarks

The PR_READ_RECEIPT_SEARCH_KEY property is ignored unless the PR_READ_RECEIPT_REQUESTED property is set to TRUE.

If a client application wants to receive read reports itself, it can leave PR_READ_RECEIPT_SEARCH_KEY unset or set it to the search key contained in the PR_SENDER_SEARCH_KEY property at message submission time.

See Also

Report Recipient Properties


PR_RECEIPT_TIME

The PR_RECEIPT_TIME property contains the date and time a delivery report is generated.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Report message objects
Identifier: | 0x002A
Property type: | PT_SYSTIME
Property tag: | 0x002A0040
Corresponding X.400 attribute: | IM_RECEIPT_TIME

Remarks

The PR_RECEIPT_TIME property must be set by the message store provider receiving the original message and generating the report. The report is usually generated with the IMAPISupport::ReadReceipt method.

See Also

Time Properties, PR_REPORT_ENTRYID


PR_RECEIVE_FOLDER_SETTINGS

The PR_RECEIVE_FOLDER_SETTINGS property contains a table of a message store's receive folder settings.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message store objects
Identifier: | 0x3415
Property type: | PT_OBJECT
Property tag: | 0x3415000D

Remarks

The PR_RECEIVE_FOLDER_SETTINGS property can be excluded in IMAPIProp::CopyTo operations or included in IMAPIProp::CopyProps operations. As a property of type PT_OBJECT, it cannot be successfully retrieved by the IMAPIProp::GetProps method; its contents should be accessed by the IMAPIProp::OpenProperty method, requesting the interface with identifier IID_IMAPITable. Service providers must report it to the IMAPIProp::GetPropList method if it is set, but can optionally report it or not if it is not set.

To retrieve table contents, a client application should call the IMsgStore::GetReceiveFolderTable method. For more information, see Receive Folder Tables.

PR_RECEIVE_FOLDER_SETTINGS contains a table of mappings of the receive folders for the message store. Calling OpenProperty on this property is equivalent to calling GetReceiveFolderTable on the message store.

See Also

Table Access Properties


PR_RECEIVED_BY_ADDRTYPE

The PR_RECEIVED_BY_ADDRTYPE property contains the e-mail address type, such as SMTP, for the messaging user that actually receives the message.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0075
Property type: | PT_TSTRING
Property tag: | 0x0075001E (0x0075001F for Unicode)

Remarks

The PR_RECEIVED_BY_ADDRTYPE property is one of the address properties for the messaging user that actually receives the message. It must be set by the incoming transport provider.

The address type string can contain only the uppercase alphabetic characters A through Z and the numbers 0 through 9. PR_RECEIVED_BY_ADDRTYPE qualifies the PR_RECEIVED_BY_EMAIL_ADDRESS property by specifying an address type, such as SMTP, thereby indicating how the address should be constructed.

For more information on the address properties, see Base Address Properties.

See Also

Actual Recipient Properties, PR_ADDRTYPE


PR_RECEIVED_BY_EMAIL_ADDRESS

The PR_RECEIVED_BY_EMAIL_ADDRESS property contains the e-mail address for the messaging user that actually receives the message.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0076
Property type: | PT_TSTRING
Property tag: | 0x0076001E (0x0076001F for Unicode)

Remarks

The PR_RECEIVED_BY_EMAIL_ADDRESS property is one of the address properties for the messaging user that actually receives the message. It must be set by the incoming transport provider.

For more information on the address properties, see Base Address Properties.

See Also

Actual Recipient Properties, PR_EMAIL_ADDRESS


PR_RECEIVED_BY_ENTRYID

The PR_RECEIVED_BY_ENTRYID property contains the entry identifier of the messaging user that actually receives the message.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x003F
Property type: | PT_BINARY
Property tag: | 0x003F0102

Remarks

The PR_RECEIVED_BY_ENTRYID property is one of the address properties for the messaging user that actually receives the message. It must be set by the incoming transport provider.

For more information on the address properties, see Base Address Properties.

PR_RECEIVED_BY_ENTRYID corresponds to an X.400 delivery envelope per-message MH_T_ attribute.

See Also

Actual Recipient Properties, PR_ENTRYID


PR_RECEIVED_BY_NAME

The PR_RECEIVED_BY_NAME property contains the display name of the messaging user that actually receives the message.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0040
Property type: | PT_TSTRING
Property tag: | 0x0040001E (0x0040001F for Unicode)
Corresponding X.400 attribute: | MH_T_ACTUAL_RECIPIENT_NAME

Remarks

The PR_RECEIVED_BY_NAME property is one of the address properties for the messaging user that actually receives the message. It must be set by the incoming transport provider.

For more information on the address properties, see Base Address Properties.

See Also

Actual Recipient Properties, PR_DISPLAY_NAME


PR_RECEIVED_BY_SEARCH_KEY

The PR_RECEIVED_BY_SEARCH_KEY property contains the search key of the messaging user that actually receives the message.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0051
Property type: | PT_BINARY
Property tag: | 0x00510102

Remarks

The PR_RECEIVED_BY_SEARCH_KEY property is one of the address properties for the messaging user that actually receives the message. It must be set by the incoming transport provider.

For more information on the address properties, see Base Address Properties.

See Also

Actual Recipient Properties, PR_SEARCH_KEY


PR_RECIPIENT_CERTIFICATE

The PR_RECIPIENT_CERTIFICATE property contains a message recipient's ASN.1 certificate for use in a report.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects
Identifier: | 0x0C13
Property type: | PT_BINARY
Property tag: | 0x0C130102
Corresponding X.400 attribute: | MH_T_RECEIPT_CERTIFICATE

Remarks

The PR_RECIPIENT_CERTIFICATE property is a copy of the recipient's PR_USER_CERTIFICATE property for use in a report. It can be used to prove to the originator that the recipient actually received the message, which a delivery report does not necessarily indicate.

See Also

Certificate Properties, PR_RECIPIENT_NUMBER_FOR_ADVICE


PR_RECIPIENT_NUMBER_FOR_ADVICE

The PR_RECIPIENT_NUMBER_FOR_ADVICE property contains a message recipient's voice telephone number to call to advise of the physical delivery of a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects
Identifier: | 0x0C14
Property type: | PT_TSTRING
Property tag: | 0x0C14001E (0x0C14001F for Unicode)
Corresponding X.400 attribute: | MH_T_RECIP_NUMBER_FOR_ADVICE

Remarks

The PR_RECIPIENT_NUMBER_FOR_ADVICE property is meant to be used in conjunction with delivery to a physical destination, rather than an electronic mailbox, when the human recipient is not expected to be present at delivery. An example is the telephone number usually included on a fax cover sheet.

See Also

PR_RECIPIENT_REASSIGNMENT_PROHIBITED


PR_RECIPIENT_REASSIGNMENT_PROHIBITED

The PR_RECIPIENT_REASSIGNMENT_PROHIBITED property contains TRUE if recipient reassignment is prohibited.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x002B
Property type: | PT_BOOLEAN
Property tag: | 0x002B000B
Corresponding X.400 attribute: | MH_T_REASSIGNMENT_PROHIBITED

See Also

Message Properties


PR_RECIPIENT_STATUS

The PR_RECIPIENT_STATUS property contains a value used by the MAPI spooler in assigning delivery responsibility among transport providers.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x0E15
Property type: | PT_LONG
Property tag: | 0x0E150003

Remarks

Do not use this property. It is reserved for use by MAPI.

See Also

Reserved Properties


PR_RECIPIENT_TYPE

The PR_RECIPIENT_TYPE property contains the recipient type for a message recipient.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Recipient subobjects
Identifier: | 0x0C15
Property type: | PT_LONG
Property tag: | 0x0C150003

Remarks

The recipient type contained in the PR_RECIPIENT_TYPE property consists of one required value and one optional flag.

PR_RECIPIENT_TYPE must contain exactly one of the following values:

MAPI_TO
The recipient is a primary (To) recipient. Clients are required to handle primary recipients; all other types are optional.
MAPI_CC
The recipient is a carbon copy (CC) recipient, a recipient that receives a message in addition to the primary recipients.
MAPI_BCC
The recipient is a blind carbon copy (BCC) recipient. Primary and carbon copy recipients are unaware of the existence of BCC recipients.
MAPI_P1
The recipient did not successfully receive the message on the previous attempt. This is a resend of an earlier transmission.

In addition, the following flag can be set:

MAPI_SUBMITTED
The recipient has already received the message and does not need to receive it again. This is a resend of an earlier transmission. This flag is set in conjunction with the MAPI_TO, MAPI_CC, and MAPI_BCC values.

The MAPI_P1 value and the MAPI_SUBMITTED flag are used when a message is being retransmitted due to nondelivery to one or more of the intended recipients. For this retransmission, the client sets MAPI_SUBMITTED on every recipient that does not need the message again but should be displayed in the recipient list. For every recipient that did not receive the message previously, the client retains the original recipient with its PR_RECIPIENT_TYPE value unchanged, but additionally submits a copy of the recipient with MAPI_P1 in place of the original value. This copy, which is discarded before actual delivery, forces the recipient into the P1 envelope and guarantees physical retransmission to that recipient. The PR_RESPONSIBILITY property is set to FALSE for MAPI_P1 recipients.

When a client displays a resend form, only the MAPI_P1 recipients are visible. Unless the user enters additional recipients, when the message is delivered, the recipient list appears exactly as it did when the message was sent for the first time.

The PR_DISPLAY_TO, PR_DISPLAY_CC, and PR_DISPLAY_BCC properties are related to recipient type. When a client calls a message's IMAPIProp::SaveChanges and there is at least one recipient in the recipient list, the message store provider sets these properties as follows:

Property | Description
PR_DISPLAY_TO | Set to TRUE if one or more of the recipients are MAPI_TO recipients.
PR_DISPLAY_CC | Set to TRUE if one or more of the recipients are MAPI_CC recipients.
PR_DISPLAY_BCC | Set to TRUE if one or more of the recipients are MAPI_BCC recipients.

In X.400, the P1 or delivery envelope is the information needed to deliver a message, including the recipient's address properties and any option flags controlling delivery and replies. The P2 or display envelope is the information usually displayed to each recipient other than the message text itself. It typically includes the subject, importance, priority, sensitivity, and submission time, as well as the primary and copied recipient names.

See Also

PR_RECIPIENT_STATUS, PR_DISPLAY_TO, PR_DISPLAY_BCC, PR_DISPLAY_CC


PR_RECORD_KEY

The PR_RECORD_KEY property contains a unique binary-comparable identifier for a specific object.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Address book container, attachment, distribution list, folder, messaging user, message, and message store objects
Identifier: | 0x0FF9
Property type: | PT_BINARY
Property tag: | 0x0FF90102

Remarks

The PR_RECORD_KEY property facilitates locating references to an object, such as finding its row in a contents table. PR_RECORD_KEY cannot be used to open an object; use the entry identifier for that purpose.

An attachment subobject should be uniquely identified within a message by PR_RECORD_KEY. This identifier is the only attachment characteristic guaranteed to stay the same after the message is closed and reopened. The store provider must preserve PR_RECORD_KEY across sessions to ensure this guarantee.

For folders, this property contains a key used in the folder hierarchy table. Typically this is the same value as that provided by the PR_ENTRYID property.

For message stores, this property is identical to the PR_STORE_RECORD_KEY property.

In a message store object, PR_RECORD_KEY should be unique across all store providers. One way to do this is to combine the value of the PR_MDB_PROVIDER property for the store (unique to that provider type) with a GUID structure or other value unique to the specific message store.

PR_RECORD_KEY is always available through the IMAPIProp::GetProps method following the first call to the IMAPIProp::SaveChanges method. Some providers can make it available immediately after instantiation.

A client or service provider can compare PR_RECORD_KEY values using memcmp. This is not possible for entry identifier values. However, PR_RECORD_KEY is guaranteed to be unique only within the same message store or address book container; two objects from different containers can have the same PR_RECORD_KEY value.

One distinction between the record and search keys is that the record key is specific to the object, whereas the search key can be copied to other objects. For example, two copies of the object can have the same PR_SEARCH_KEY value but must have different PR_RECORD_KEY values.

The following table summarizes important differences among PR_ENTRYID, PR_RECORD_KEY, and PR_SEARCH_KEY.

Characteristic | PR_ENTRYID | PR_RECORD_KEY | PR_SEARCH_KEY
Required on attachment objects | No | Yes | No
Required on folder objects | Yes | Yes | No
Required on message store objects | Yes | Yes | No
Required on status objects | Yes | No | No
Creatable by client | No | No | Yes
Available before a call to SaveChanges | Maybe | Maybe | Messages — Yes Others — Maybe
Changed in a copy operation | Yes | Yes | No
Changeable by a client after a copy | No | No | Yes
Unique within ... | Entire world | Provider instance | Entire world
Binary comparable (as with memcmp) | No -- use IMAPISupport:: CompareEntryIDs | Yes | Yes

See Also

General Object Properties


PR_REDIRECTION_HISTORY

The PR_REDIRECTION_HISTORY property contains information about the route covered by a delivered message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x002C
Property type: | PT_BINARY
Property tag: | 0x002C0102
Corresponding X.400 attribute: | MH_T_REDIRECTION_HISTORY

Remarks

The PR_REDIRECTION_HISTORY property is used when a message is autoforwarded by an automatic agent.

See Also

Autoforwarding Properties


PR_REGISTERED_MAIL_TYPE

The PR_REGISTERED_MAIL_TYPE property contains the type of registration used for physical delivery of a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0C16
Property type: | PT_LONG
Property tag: | 0x0C160003
Corresponding X.400 attribute: | MH_T_REGISTRATION

See Also

Physical Delivery Properties, PR_X400_CONTENT_TYPE


PR_RELATED_IPMS

The PR_RELATED_IPMS property contains a list of identifiers for messages to which a message is related.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x002D
Property type: | PT_BINARY
Property tag: | 0x002D0102
Corresponding X.400 attribute: | IM_RELATED_IPMS

Remarks

The identifiers use the same specific construction rules as are used for the PR_SEARCH_KEY property.

See Also

Conversation Properties


PR_REMOTE_PROGRESS

The PR_REMOTE_PROGRESS property contains a number indicating the status of a remote transfer.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x3E0B
Property type: | PT_LONG
Property tag: | 0x3E0B0003

Remarks

If no transfer is in progress, the PR_REMOTE_PROGRESS property should be set to –1. If a transfer is in progress, it should be set to a value from 0 to 100 indicating the transfer's percent of completion.

The text associated with the numeric status code appears in the PR_REMOTE_PROGRESS_TEXT property.

The following flags can be set for PR_REMOTE_PROGRESS:

MSGSTATUS_REMOTE_DELETE
The message transfer is deleted.
MSGSTATUS_REMOTE_DOWNLOAD
The message transfer is in progress.

See Also

Remote Transfer Properties


PR_REMOTE_PROGRESS_TEXT

The PR_REMOTE_PROGRESS_TEXT property contains an ASCII string indicating the status of a remote transfer.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x3E0C
Property type: | PT_TSTRING
Property tag: | 0x3E0C001E (0x3E0C001F for Unicode)

Remarks

A numeric code associated with this text is passed in the PR_REMOTE_PROGRESS property.

See Also

Remote Transfer Properties


PR_REMOTE_VALIDATE_OK

The PR_REMOTE_VALIDATE_OK property contains TRUE if the remote viewer is allowed to call the IMAPIStatus::ValidateState method.

Quick Info

Header file: | MAPITAGS.H
May be a column in: | Status tables
Identifier: | 0x3E0D
Property type: | PT_BOOLEAN
Property tag: | 0x3E0D000B

Remarks

The PR_REMOTE_VALIDATE_OK property appears in the status table and offers some control over transport performance. It can be considered as another way of directing the remote viewer to idle. When it is set to TRUE, the remote viewer can call IMAPIStatus::ValidateState as often as desired. A value of FALSE indicates that the remote viewer cannot make any more calls.

The transport provider usually sets this property dynamically, setting the value to FALSE to disable additional calls when the transport provider has a sufficient amount of processing to perform. When the transport provider is done, it then sets the value to TRUE to allow the client application to make further IMAPIStatus::ValidateState calls.

See Also

Remote Transfer Properties


PR_RENDERING_POSITION

The PR_RENDERING_POSITION property contains an offset, in characters, to use in rendering an attachment within the main message text.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Attachment subobjects
Identifier: | 0x370B
Property type: | PT_LONG
Property tag: | 0x370B0003

Remarks

When the supplied offset is –1 (0xFFFFFFFF), the attachment is not rendered using the PR_RENDERING_POSITION property. All values other than –1 indicate the position within PR_BODY at which the attachment is to be rendered.

Note The character at PR_RENDERING_POSITION in PR_BODY is replaced by the attachment. Typically this character is a space, although a special placeholder character can also be used.

PR_RENDERING_POSITION is expressed in characters. In some character sets this is not equivalent to bytes. Unicode applications can compute the position based on two-byte characters. Double-Byte Character Set (DBCS) applications must scan the text up to the PR_RENDERING_POSITION value, because their character representation varies between one and two bytes per character.

This property should not be used with Rich Text Format (RTF) text. The rendering position is indicated in RTF by an escape sequence called the object attachment placeholder. This sequence consists of the string \objattph followed by a single character, normally a space, that will be replaced by the attachment rendering.

See Also

Attachment Properties


PR_REPLY_RECIPIENT_ENTRIES

The PR_REPLY_RECIPIENT_ENTRIES property contains a sized array of entry identifiers for recipients that are to get a reply.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x004F
Property type: | PT_BINARY
Property tag: | 0x004F0102
Corresponding X.400 attribute: | IM_REPLY_RECIPIENTS

Remarks

The PR_REPLY_RECIPIENT_ENTRIES property contains a FLATENTRYLIST structure and is not a multivalued property.

When this property is not present, a reply is sent only to the user identified by PR_SENDER_ENTRYID. When PR_REPLY_RECIPIENT_ENTRIES and PR_REPLY_RECIPIENT_NAMES are defined, the reply is sent to all of the recipients identified by these two properties. A transport provider uses these properties to override the usual reply logic.

If either PR_REPLY_RECIPIENT_ENTRIES or PR_REPLY_RECIPIENT_NAMES is set, the other property must be set also. These properties must contain the same number of recipients, and they must contain them in the same order. Failure to observe these requirements can cause unpredictable results.

See Also

Message Properties


PR_REPLY_RECIPIENT_NAMES

The PR_REPLY_RECIPIENT_NAMES property contains a list of display names for recipients that are to get a reply.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0050
Property type: | PT_TSTRING
Property tag: | 0x0050001E (0x0050001F for Unicode)

Remarks

The PR_REPLY_RECIPIENT_NAMES property contains one string, with the display names separated by semicolons.

When this property is not present, a reply is sent only to the user identified by PR_SENDER_NAME. When PR_REPLY_RECIPIENT_ENTRIES and PR_REPLY_RECIPIENT_NAMES are defined, the reply is sent to all of the recipients identified by these two properties. A transport provider uses these properties to override the usual reply logic.

If either PR_REPLY_RECIPIENT_ENTRIES or PR_REPLY_RECIPIENT_NAMES is set, the other property must be set also. These properties must contain the same number of recipients, and they must contain them in the same order. Failure to observe these requirements can cause unpredictable results.

See Also

Message Properties


PR_REPLY_REQUESTED

The PR_REPLY_REQUESTED property contains TRUE if a message sender requests a reply from a recipient.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0C17
Property type: | PT_BOOLEAN
Property tag: | 0x0C17000B
Corresponding X.400 attribute: | IM_REPLY_REQUESTED

See Also

Message Properties, PR_REPLY_TIME


PR_REPLY_TIME

The PR_REPLY_TIME property contains the date and time by which a reply is expected for a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0030
Property type: | PT_SYSTIME
Property tag: | 0x00300040
Corresponding X.400 attribute: | IM_REPLY_TIME

See Also

Time Properties, PR_REPLY_REQUESTED


PR_REPORT_ENTRYID

The PR_REPORT_ENTRYID property contains the entry identifier for the recipient that should get reports for this message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0045
Property type: | PT_BINARY
Property tag: | 0x00450102

Remarks

The PR_REPORT_ENTRYID property is one of the address properties for the recipient that the sender has delegated to receive any reports generated for this message.

A client application that needs to route reports to another user should set this property at message submission time. If it is not set, the reports are sent to the message sender.

For more information on the address properties, see Base Address Properties.

See Also

Report Recipient Properties, PR_SENDER_ENTRYID


PR_REPORT_NAME

The PR_REPORT_NAME property contains the display name for the recipient that should get reports for this message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x003A
Property type: | PT_TSTRING
Property tag: | 0x003A001E (0x003A001F for Unicode)

Remarks

The PR_REPORT_NAME property is one of the address properties for the recipient that the sender has delegated to receive any reports generated for this message.

A client application that needs to route reports to another user should set this property at message submission time. If it is not set, the reports are sent to the message sender.

For more information on the address properties, see Base Address Properties.

See Also

Report Recipient Properties, PR_SENDER_NAME


PR_REPORT_SEARCH_KEY

The PR_REPORT_SEARCH_KEY property contains the search key for the recipient that should get reports for this message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0054
Property type: | PT_BINARY
Property tag: | 0x00540102

Remarks

The PR_REPORT_SEARCH_KEY property is one of the address properties for the recipient that the sender has delegated to receive any reports generated for this message.

A client application that needs to route reports to another user should set this property at message submission time. If it is not set, the reports are sent to the message sender.

For more information on the address properties, see Base Address Properties.

See Also

Report Recipient Properties, PR_SENDER_SEARCH_KEY


PR_REPORT_TAG

The PR_REPORT_TAG property contains a binary tag value that the messaging system should copy to any report generated for the message.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0031
Property type: | PT_BINARY
Property tag: | 0x00310102

Remarks

The PR_REPORT_TAG property, like the PR_SUBJECT_IPM property property, is used to correlate a report with the original message.

See Also

Report Properties, PR_REPORT_NAME


PR_REPORT_TEXT

The PR_REPORT_TEXT property contains optional text for a report generated by the messaging system.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x1001
Property type: | PT_TSTRING
Property tag: | 0x1001001E (0x1001001F for Unicode)

Remarks

Usually, the text contained in the PR_REPORT_TEXT property is generated in response to a delivery or nondelivery report or a read or nonread report received from the underlying messaging system, but is not itself text that was transferred through that system.

See Also

Report Properties


PR_REPORT_TIME

The PR_REPORT_TIME property contains the date and time when the messaging system generated a report.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Read and nonread report message objects and recipient subobjects within delivery and nondelivery report message objects
Identifier: | 0x0032
Property type: | PT_SYSTIME
Property tag: | 0x00320040

Remarks

The PR_REPORT_TIME property represents a per-recipient property on delivery and nondelivery reports and a per-message property on read and nonread reports.

See Also

Time Properties


PR_REPORTING_DL_NAME

The PR_REPORTING_DL_NAME property contains the display name of a distribution list for which the messaging system is delivering a report.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Report message objects
Identifier: | 0x1003
Property type: | PT_BINARY
Property tag: | 0x10030102
Corresponding X.400 attribute: | MH_T_REPORTING_DL_NAME

See Also

Report Properties


PR_REPORTING_MTA_CERTIFICATE

The PR_REPORTING_MTA_CERTIFICATE property contains an identifier for the message transfer agent that generated a report.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Report message objects
Identifier: | 0x1004
Property type: | PT_BINARY
Property tag: | 0x10040102
Corresponding X.400 attribute: |

Remarks

The PR_REPORTING_MTA_CERTIFICATE property corresponds to an X.400 report per-message attribute.

See Also

Report Properties, PR_ORIGINATING_MTA_CERTIFICATE


PR_REQUESTED_DELIVERY_METHOD

The PR_REQUESTED_DELIVERY_METHOD property contains a binary array of delivery methods (service providers), in order of a message sender's preference.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0C18
Property type: | PT_BINARY
Property tag: | 0x0C180102
Corresponding X.400 attribute: | MH_T_PREFERRED_DELIVERY_MODE

Remarks

The array contained in the PR_REQUESTED_DELIVERY_METHOD property consists of 32-bit ASN.1 identifiers for each of the service providers. Typical identifier values are MH_DM_TELEX and MH_DM_G3FAX.

See Also

Message Properties, PR_PROOF_OF_DELIVERY_REQUESTED


PR_RESOURCE_FLAGS

The PR_RESOURCE_FLAGS property contains a bitmask of flags for message services and providers.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Status objects
Must be a column in: | Message service, message store, and status tables
Identifier: | 0x3009
Property type: | PT_LONG
Property tag: | 0x30090003

Remarks

PR_RESOURCE_FLAGS describes the characteristics of a message service, a service provider, or a status object. The flags that are set for PR_RESOURCE_FLAGS depend on its context. For example, some flags are valid only for status objects and other flags only for columns in the message service table.

The flags are of three classes: static, modifiable, and dynamic. Static flags are set by MAPI from data in MAPISVC.INF and never altered. Modifiable flags are set by MAPI from MAPISVC.INF but can be subsequently changed. Dynamic flags can be set and reset by MAPI methods.

For a message service, one or more of the following flags can be set in PR_RESOURCE_FLAGS:

SERVICE_CREATE_WITH_STORE
Reserved. Do not use.
SERVICE_DEFAULT_STORE
Dynamic. The message service contains the default store. A user interface should be displayed prompting the user for confirmation before deleting or moving this service out of the profile.
SERVICE_NO_PRIMARY_IDENTITY
Static. The service level flag that should be set to indicate that none of the providers in the message service can be used to supply an identity. Either this flag or SERVICE_PRIMARY_IDENTITY should be set, but not both.
SERVICE_PRIMARY_IDENTITY
Modifiable. The corresponding message service contains the provider used for the primary identity for this session. Use IMsgServiceAdmin::SetPrimaryIdentity to set this flag. Either this flag or SERVICE_NO_PRIMARY_IDENTITY should be set, but not both.
SERVICE_SINGLE_COPY
Static. Any attempt to create or copy this message service into a profile where the service already exists will fail. To create a single copy message service add the PR_RESOURCE_FLAGS property to the service's section in MAPISVC.INF and set this flag.

For a service provider, one or more of the following flags can be set in PR_RESOURCE_FLAGS:

HOOK_INBOUND
Static. The spooler hook needs to process inbound messages.
HOOK_OUTBOUND
Static. The spooler hook needs to process outbound messages.
STATUS_DEFAULT_OUTBOUND
Modifiable. This identity should be applied to outbound messages if the profile contains multiple instances of this transport provider. This can happen if multiple instances of a single transport provider appear in the profile.
STATUS_DEFAULT_STORE
Modifiable. This message store is the default store for the profile.
STATUS_NEED_IPM_TREE
Dynamic. The standard folders in this message store, including the interpersonal message (IPM) root folder, have not yet been verified. MAPI sets and clears this flag.
STATUS_NO_DEFAULT_STORE
Static. This message store is incapable of becoming the default message store for the profile.
STATUS_NO_PRIMARY_IDENTITY
Static. This provider does not furnish an identity in its status row. Either this flag or STATUS_PRIMARY_IDENTITY must be set.
STATUS_OWN_STORE
Static. This transport provider is tightly coupled with a message store and furnishes the PR_OWN_STORE_ENTRYID property in its status row.
STATUS_PRIMARY_IDENTITY
Modifiable. This provider furnishes the primary identity for the session; the entry identifier for the object furnishing the identity is returned from IMAPISession::QueryIdentity. Either this flag or STATUS_NO_PRIMARY_IDENTITY must be set.
STATUS_PRIMARY_STORE
Modifiable. This message store is to be used when a client application logs on. Once opened, this store should be set as the default store for the profile.
STATUS_SECONDARY_STORE
Modifiable. This message store is to be used if the primary store is not available when a client application logs on. Once opened, this store should be set as the default store for the profile.
STATUS_SIMPLE_STORE
Dynamic. This message store will be used by Simple MAPI or CMC as its default message store.
STATUS_TEMP_SECTION
Dynamic. This message store should not be published in the message store table and will be deleted from the profile after logoff.
STATUS_XP_PREFER_LAST
Static. This transport expects to be the last transport selected to send a message when multiple transport providers are able to transmit the message.

See Also

Provider Properties, IMsgServiceAdmin::MsgServiceTransportOrder, PR_IDENTITY_ENTRYID


PR_RESOURCE_METHODS

The PR_RESOURCE_METHODS property contains a bitmask of flags indicating the methods in the IMAPIStatus interface that are supported by the status object.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Status objects
Must be a column in: | Status tables
Identifier: | 0x3E02
Property type: | PT_LONG
Property tag: | 0x3E020003

Remarks

PR_RESOURCE_METHODS indicates which of the methods in a status object's implementation of IMAPIStatus are supported. Status objects are allowed to return MAPI_E_NO_SUPPORT from unsupported methods.

Clients use a status object's PR_RESOURCE_METHODS property to avoid making calls to unsupported methods. If the flag that corresponds to a particular method is set, the method exists and can be called. If that flag is clear, the method should not be called.

The status objects implemented by MAPI support the following methods:

Status object | Supported methods
MAPI subsystem | ValidateState only
MAPI address book | ValidateState only
MAPI spooler | ValidateState and FlushQueues

One or more of the following flags can be set in PR_RESOURCE_METHODS:

STATUS_CHANGE_PASSWORD
Indicates that the IMAPIStatus::ChangePassword method is supported.
STATUS_FLUSH_QUEUES
Indicates that the IMAPIStatus::FlushQueues method is supported.
STATUS_SETTINGS_DIALOG
Indicates that the IMAPIStatus::SettingsDialog method is supported.
STATUS_VALIDATE_STATE
Indicates that the IMAPIStatus::ValidateState method is supported.


PR_RESOURCE_PATH

The PR_RESOURCE_PATH property contains a path to the service provider's server.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Status objects
May be a column in: | Status tables
Identifier: | 0x3E07
Property type: | PT_TSTRING
Property tag: | 0x3E07001E (0x3E07001F for Unicode)

Remarks

The path contained in the PR_RESOURCE_PATH property represents the suggested path where the user can find resources. The definition of the property is provider specific. For example, a scheduling application uses this property to specify the suggested location for its scheduling application files.

The messaging user profile furnishes PR_RESOURCE_PATH as a convenience so that a client application does not have to prompt the messaging user for a network path or network drive letter.

MAPI works only with filenames, and other strings passed to it, in the ANSI character set. Applications that use filenames in an OEM character set must convert them to ANSI before calling MAPI.

See Also

Provider Properties


PR_RESOURCE_TYPE

The PR_RESOURCE_TYPE property contains a value indicating the service provider type.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Provider objects
Identifier: | 0x3E03
Property type: | PT_LONG
Property tag: | 0x3E030003

Remarks

The PR_RESOURCE_TYPE property can have exactly one of the following values:

MAPI_AB
Address book
MAPI_AB_PROVIDER
Address book provider
MAPI_HOOK_PROVIDER
Spooler hook provider
MAPI_PROFILE_PROVIDER
Profile provider
MAPI_SPOOLER
Message spooler
MAPI_STORE_PROVIDER
Message store provider
MAPI_SUBSYSTEM
Internal MAPI subsystem
MAPI_TRANSPORT_PROVIDER
Transport provider

See Also

Provider Properties


PR_RESPONSE_REQUESTED

The PR_RESPONSE_REQUESTED property contains TRUE if the message sender wants a response to a meeting request.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects used for scheduling
Identifier: | 0x0063
Property type: | PT_BOOLEAN
Property tag: | 0x0063000B

Remarks

The PR_RESPONSE_REQUESTED property is used for meeting requests. The receiving client application should prompt the user to accept or decline the request and then send this response back to the sender.

See Also

Schedule Properties


PR_RESPONSIBILITY

The PR_RESPONSIBILITY property contains TRUE if some transport provider has already accepted responsibility for delivering the message to this recipient, and FALSE if the MAPI spooler considers that this transport provider should accept responsibility.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Recipient subobjects
Identifier: | 0x0E0F
Property type: | PT_BOOLEAN
Property tag: | 0x0E0F000B
Corresponding X.400 attribute: | MH_T_MTA_RESPONSIBILITY

Remarks

When the MAPI spooler presents an outbound message to a transport provider, through IXPLogon::SubmitMessage, it sets the PR_RESPONSIBILITY property to FALSE for all recipients for which the MAPI spooler considers that transport provider responsible, and TRUE for all other recipients. The transport provider should attempt to handle all recipients with PR_RESPONSIBILITY set to FALSE. After successfully sending, or conclusively failing to send, to a recipient, the transport provider should set PR_RESPONSIBILITY to TRUE in the source message to indicate that it has accepted responsibility for that recipient.

If, after examining a recipient, a transport provider decides that it cannot or should not handle it, the transport provider should leave PR_RESPONSIBILITY set to FALSE. The MAPI spooler will then look for another transport provider that can handle that recipient. The MAPI spooler ultimately creates a nondelivery report for any recipients for which no transport provider accepts responsibility.

If the transport provider attempts and fails to deliver the message, it should call the IMAPISupport::StatusRecips method to indicate to MAPI the reasons for the failure, so that MAPI can generate a nondelivery report.

See Also

PR_DELETE_AFTER_SUBMIT


PR_RETURNED_IPM

The PR_RETURNED_IPM property contains TRUE if the original message is being returned with a nonread report.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Report message objects
Identifier: | 0x0033
Property type: | PT_BOOLEAN
Property tag: | 0x0033000B

Remarks

An X.400 transport provider sets the PR_RETURNED_IPM property in the nonread report.

See Also

Report Properties


PR_ROW_TYPE

The PR_ROW_TYPE property contains a value that indicates the type of a row in a table.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | Contents tables
Identifier: | 0x0FF5
Property type: | PT_LONG
Property tag: | 0x0FF50003

Remarks

The PR_ROW_TYPE property appears only on contents tables. A category only exists when it has items.

PR_ROW_TYPE can have exactly one of the following values:

TBL_LEAF_ROW
Represents actual data, rather than a category row.
TBL_EMPTY_CATEGORY
Not currently used.
TBL_EXPANDED_CATEGORY
The category is expanded; the user interface usually displays this with the minus sign ( – ) next to it.
TBL_COLLAPSED_CATEGORY
The category is collapsed; the user interface usually displays this with the plus sign (+) next to it.

See Also

Table Row Properties, PR_ROWID


PR_ROWID

The PR_ROWID property contains a unique identifier for a recipient in a recipient table or status table.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | Recipient tables and status tables
Identifier: | 0x3000
Property type: | PT_LONG
Property tag: | 0x30000003

Remarks

The PR_ROWID property is a temporary value that is valid only for the life of the object that owns the table. It appears as a column of the table but is not stored.

See Also

Table Row Properties, IMessage::GetRecipientTable, IMessage::ModifyRecipients


PR_RTF_COMPRESSED

The PR_RTF_COMPRESSED property contains the Rich Text Format version of the message text, usually in compressed form.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x1009
Property type: | PT_BINARY
Property tag: | 0x10090102

Remarks

The PR_RTF_COMPRESSED property contains the same message text as the PR_BODY property but in Rich Text Format (RTF).

Message text in RTF is normally stored in compressed form. However, some systems do not compress formatted text. To accommodate them, MAPI provides the dwMagicUncompressedRTF value for a stream header to identify uncompressed RTF, and the STORE_UNCOMPRESSED_RTF flag in PR_STORE_SUPPORT_MASK for the message store to indicate it can store uncompressed RTF.

To obtain the contents of PR_RTF_COMPRESSED, call OpenProperty, then call WrapCompressedRTFStream with the MAPI_READ flag. To write into PR_RTF_COMPRESSED, open it with the MAPI_MODIFY and MAPI_CREATE flags. This ensures that the new data completely replace any old data and that the writes are performed using the minimum number of store updates.

Message stores that support RTF ignore any changes to white space in the message text. When PR_BODY is stored for the first time, the message store also generates and stores PR_RTF_COMPRESSED. If the IMAPIProp::SaveChanges method is subsequently called and PR_BODY has been modified, the message store calls the RTFSync function to ensure synchronization with the RTF version. If only white space has been changed, the properties are left unchanged. This preserves any nontrivial RTF formatting when the message travels through non-RTF-aware clients and messaging systems.

See Also

Rich Text Properties


PR_RTF_IN_SYNC

The PR_RTF_IN_SYNC property contains TRUE if PR_RTF_COMPRESSED has the same text content as PR_BODY for this message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0E1F
Property type: | PT_BOOLEAN
Property tag: | 0x0E1F000B

Remarks

A value of TRUE means that the PR_BODY property, the plain text version of this message, and the PR_RTF_COMPRESSED property, the Rich Text Format version, are identical except for white space in PR_BODY and formatting in PR_RTF_COMPRESSED. The text in the two versions consists of the same characters in the same sequence.

A value of FALSE means that the two versions are not synchronized for text content but are capable of being synchronized by the RTFSync function. One version has been altered and the other version has not.

No value, PR_RTF_IN_SYNC is not set at all, means that the two versions, if both exist or ever existed, cannot be synchronized. One version has been deleted or altered so radically that synchronization is no longer possible.

A client application that has modified PR_RTF_COMPRESSED should set a value of FALSE in PR_RTF_IN_SYNC to force synchronization. RTF-aware message stores should perform the synchronization using RTFSync during an IMAPIProp::SaveChanges call. RTF-aware clients should check the setting of PR_RTF_IN_SYNC before reading PR_RTF_COMPRESSED, and call RTFSync first if necessary.

If PR_BODY has had modifications to anything other than its white space, the message store must delete PR_RTF_IN_SYNC to terminate synchronization.

See Also

Rich Text Properties


PR_RTF_SYNC_BODY_COUNT

The PR_RTF_SYNC_BODY_COUNT property contains a count of the significant characters of the message text.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x1007
Property type: | PT_LONG
Property tag: | 0x10070003

Remarks

The RTFSync function computes the count of characters in the text using only those that it considers to be significant to the message. For example, some white space and other ignorable characters are omitted from the count.

The PR_RTF_SYNC_BODY_COUNT property is an RTF auxiliary property. These properties are used by the RTFSync function and are not intended to be used directly by client applications.

See Also

Reserved Properties


PR_RTF_SYNC_BODY_CRC

The PR_RTF_SYNC_BODY_CRC property contains the cyclical redundancy check (CRC) computed for the message text.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x1006
Property type: | PT_LONG
Property tag: | 0x10060003

Remarks

The RTFSync function computes the CRC using only the characters that it considers to be significant to the message. For example, some white space and other ignorable characters are omitted from the CRC.

The PR_RTF_SYNC_BODY_CRC property is a Rich Text Format auxiliary property. These properties are used by the RTFSync function and are not intended to be used directly by client applications.

See Also

Reserved Properties


PR_RTF_SYNC_BODY_TAG

The PR_RTF_SYNC_BODY_TAG property contains significant characters that appear at the beginning of the message text.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x1008
Property type: | PT_TSTRING
Property tag: | 0x1008001E (0x1008001F for Unicode)

Remarks

The RTFSync function uses the text tag to indicate the beginning of the message text. When the text is modified, the tag is used to find the beginning of the previous text.

The PR_RTF_SYNC_BODY_TAG property is a Rich Text Format auxiliary property. These properties are used by the RTFSync function and are not intended to be used directly by client applications.

See Also

Reserved Properties


PR_RTF_SYNC_PREFIX_COUNT

The PR_RTF_SYNC_PREFIX_COUNT property contains a count of the ignorable characters that appear before the significant characters of the message.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x1010
Property type: | PT_LONG
Property tag: | 0x10100003

Remarks

The count of prefix characters does not include white space.

The PR_RTF_SYNC_PREFIX_COUNT property is a Rich Text Format auxiliary property. These properties are used by the RTFSync function and are not intended to be used directly by client applications.

See Also

Reserved Properties


PR_RTF_SYNC_TRAILING_COUNT

The PR_RTF_SYNC_TRAILING_COUNT property contains a count of the ignorable characters that appear after the significant characters of the message.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x1011
Property type: | PT_LONG
Property tag: | 0x10110003

Remarks

The PR_RTF_SYNC_TRAILING_COUNT property is a Rich Text Format auxiliary property. These properties are used by the RTFSync function and are not intended to be used directly by client applications.

See Also

Reserved Properties


PR_SEARCH

The PR_SEARCH property contains a container object that is used for advanced searches.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Address book container and message store objects
Identifier: | 0x3607
Property type: | PT_OBJECT
Property tag: | 0x3607000D

Remarks

A container that does not support advanced search capabilities, does not have to supply the PR_SEARCH property.

See Also

Specialized Usage Properties, IMAPIContainer : IMAPIProp


PR_SEARCH_KEY

The PR_SEARCH_KEY property contains a binary-comparable key that identifies correlated objects for a search.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Address book container, distribution list, messaging user, and message objects
Identifier: | 0x300B
Property type: | PT_BINARY
Property tag: | 0x300B0102
Corresponding X.400 attribute: | IM_THIS_IPM

Remarks

The PR_SEARCH_KEY property provides a trace for related objects, such as message copies, and facilitates finding unwanted occurrences, such as duplicate recipients.

PR_SEARCH_KEY is one of the base address properties for all messaging users. For more information on the base address properties, see Base Address Properties.

MAPI uses specific rules for constructing search keys for message recipients. The search key is formed by concatenating the address type (in uppercase characters), the colon character ':', the e-mail address in canonical form, and the terminating null character. Canonical form here means that case-sensitive addresses appear in the correct case, and addresses that are not case-sensitive are converted to uppercase. This is important in preserving correlations among messages.

For message objects, PR_SEARCH_KEY is available through the IMAPIProp::GetProps method immediately following message creation. For other objects, it is available following the first call to the IMAPIProp::SaveChanges method. Because PR_SEARCH_KEY is changeable, it is unreliable to obtain it through GetProps until a SaveChanges call has committed any values set or changed by the IMAPIProp::SetProps method.

For profiles, MAPI also furnishes a hard-coded profile section named MUID_PROFILE_INSTANCE, with PR_SEARCH_KEY as its single property. This key is guaranteed to be unique among all profiles ever created, and can be more reliable than the PR_PROFILE_NAME property, which can be, for example, deleted and recreated with the same name.

The following table summarizes important differences among the PR_ENTRYID, PR_RECORD_KEY, and PR_SEARCH_KEY properties.

Characteristic | PR_ENTRYID | PR_RECORD_KEY | PR_SEARCH_KEY
Required on attachment objects | No | Yes | No
Required on folder objects | Yes | Yes | No
Required on message store objects | Yes | Yes | No
Required on status objects | Yes | No | No
Creatable by client | No | No | Yes
Available before SaveChanges | Maybe | Maybe | Messages — Yes Others — Maybe
Changed in a copy operation | Yes | Yes | No
Changeable by client after a copy | No | No | Yes
Unique within ... | Entire world | Provider instance | Entire world
Binary comparable (as with memcmp) | No -- use IMAPISupport:: CompareEntryIDs | Yes | Yes

See Also

Base Address Properties, PR_RESPONSIBILITY, PR_STORE_RECORD_KEY


PR_SECURITY

The PR_SECURITY property contains a flag that indicates the security level of a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0034
Property type: | PT_LONG
Property tag: | 0x00340003

Remarks

The underlying messaging system chooses whether to use the flag contained in the PR_SECURITY property. The PR_MESSAGE_CLASS property can determine whether the messaging system honors the security settings.

The following flags can be set:

SECURITY_SIGNED
The message has been digitally signed. The recipient can read the digital signature to see if it is expired or suspended, or if the contents have been altered since the digital signing.
SECURITY_ENCRYPTED
The message has been encrypted. The recipient must present a security password to read the message text.

See Also

Criticality Properties


PR_SELECTABLE

The PR_SELECTABLE property contains TRUE if the entry in the one-off table can be selected.

Quick Info

Header file: | MAPITAGS.H
May be a column in: | One-off tables
Identifier: | 0x3609
Property type: | PT_BOOLEAN
Property tag: | 0x3609000B

Remarks

The PR_SELECTABLE property is used primarily for visual formatting of a one-off table. X.400 or gateway templates can be grouped by creating an entry that indicates the heading for the group. Setting PR_SELECTABLE to FALSE for the heading ensures that the user can select only the actual templates in the group and not this heading entry.

This property applies only to a one-off table, not to an address book hierarchy table.

MAPI allows an address book provider to group items visually by two means. First, certain rows can function as headings by being unselectable. Second, the selectable items can be indented relative to their headings using the PR_DEPTH property. PR_SELECTABLE is used in such grouping to indicate whether or not this item can be selected from a list box to create a one-off address. For example, if a client has several templates for building FAX addresses, it can display them as follows:

FAX templates (depth 0, not selectable)
    Local (depth 1, selectable)
    Long-distance (depth 1, selectable)

See Also

Template Properties, IABLogon::GetOneOffTable, PR_FOLDER_TYPE


PR_SEND_INTERNET_ENCODING

The PR_SEND_INTERNET_ENCODING property contains a bitmask of encoding preferences.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects
Identifier: | 0x3A71
Property type: | PT_LONG
Property tag: | 0x3A710003

Remarks

You can set the PR_SEND_INTERNET_ENCODING property to set encoding options specific to the Internet.

PR_SEND_INTERNET_ENCODING can contain the following flags:

BODY_ENCODING_HTML
Encode the message text in HTML. This flag is ignored unless the ENCODING_MIME flag is set.
BODY_ENCODING_TEXT_AND_HTML
Encode the message text using text and HTML as MIME multipart alternatives. This flag is ignored unless the ENCODING_MIME flag is set.
ENCODING_MIME
Encode the message using MIME. If this flag is not set, MAPI encodes the message text in plain text and the attachments in UUENCODE.
ENCODING_PREFERENCE
Use the other flags in this bitmask to determine the encoding. If this flag is not set, MAPI leaves it to the messaging system to make encoding decisions.
MAC_ATTACH_ENCODING_APPLEDOUBLE
Encode Macintosh attachments in Apple double mode. This flag is ignored unless the ENCODING_MIME flag is set.
MAC_ATTACH_ENCODING_APPLESINGLE
Encode Macintosh attachments in Apple single mode. This flag is ignored unless the ENCODING_MIME flag is set.
MAC_ATTACH_ENCODING_UUENCODE
Encode Macintosh attachments in UUENCODE. If the ENCODING_MIME flag is set, this flag is ignored and BinHex encoding is used instead.


PR_SEND_RICH_INFO

The PR_SEND_RICH_INFO property contains TRUE if the recipient can receive all message content, including Rich Text Format and OLE objects.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Distribution list and messaging user objects
Identifier: | 0x3A40
Property type: | PT_BOOLEAN
Property tag: | 0x3A40000B

Remarks

It is recommended that distribution list and messaging user objects expose the PR_SEND_RICH_INFO property.

PR_SEND_RICH_INFO indicates whether the sender considers the recipient to be MAPI-enabled.

When this property is set to TRUE, the transport and gateway can transmit the full content of the message, including Rich Text Format and OLE objects. The transport provider and gateway should use TNEF to encapsulate any properties that are not native to all the messaging systems involved.

When this property is set to FALSE, the transport provider and gateway are free to discard message content that their native clients cannot use. For example, when the clients do not support Rich Text Format, the transport provider can send only plain text.

When PR_SEND_RICH_INFO is not set, default behavior is determined by the implementation of the transport provider, MTA, or gateway. Address book providers are not required to support this property. For example, a tightly coupled address book and transport provider can choose to send TNEF but never use Rich Text Format.

The client should not assume the transport provider and gateway will use TNEF on their own initiative. Some transport providers and gateways that support TNEF transmit it without regard to the value of PR_SEND_RICH_INFO, but others decline to construct or send TNEF if PR_SEND_RICH_INFO is not set to TRUE.

Note The setting of this property, and the decisions based on its value, are on a per-recipient basis.

By default, MAPI sets the value of PR_SEND_RICH_INFO to TRUE. A client calling IAddrBook::CreateOneOff or a provider calling IMAPISupport::CreateOneOff can set the MAPI_SEND_NO_RICH_INFO bit in the ulFlags parameter, which causes MAPI to set PR_SEND_RICH_INFO to FALSE. One-offs created by the user interface use the value specified by the creating template.

On calls to the IAddrBook::ResolveName method when the name cannot be resolved but can be interpreted as an Internet address (SMTP), PR_SEND_RICH_INFO is set to FALSE. To be construed as an Internet address, the display name of the unresolved entry must be in the format X@Y.Z, such as "pete@pinecone.com".

See Also

Rich Text Properties, PR_ATTACH_DATA_OBJ


PR_SENDER_ADDRTYPE

The PR_SENDER_ADDRTYPE property contains the message sender's e-mail address type.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0C1E
Property type: | PT_TSTRING
Property tag: | 0x0C1E001E (0x0C1E001F for Unicode)

Remarks

The PR_SENDER_ADDRTYPE property is one of the address properties for the message sender. It must be set by the outgoing transport provider, which should never propagate any previously existing values.

If no transport provider has supplied any sender address properties, the MAPI spooler attempts to fill them in by calling the IMAPISession::QueryIdentity method for an entry identifier. If no entry identifiers have been provided, the MAPI spooler stores "Unknown" in all the sender address properties of type PT_TSTRING.

For more information on the address properties, see Base Address Properties.

See Also

Sender Properties, PR_ADDRTYPE, PR_SENT_REPRESENTING_ADDRTYPE


PR_SENDER_EMAIL_ADDRESS

The PR_SENDER_EMAIL_ADDRESS property contains the message sender's e-mail address.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0C1F
Property type: | PT_TSTRING
Property tag: | 0x0C1F001E (0x0C1F001F for Unicode)

Remarks

The PR_SENDER_EMAIL_ADDRESS property is one of the address properties for the message sender. It must be set by the outgoing transport provider, which should never propagate any previously existing values.

If no transport provider has supplied any sender address properties, the MAPI spooler attempts to fill them in by calling the IMAPISession::QueryIdentity method for an entry identifier. If no entry identifiers have been provided, the MAPI spooler stores "Unknown" in all the sender address properties of type PT_TSTRING.

For more information on the address properties, see Base Address Properties.

See Also

Sender Properties, PR_EMAIL_ADDRESS, PR_SENT_REPRESENTING_EMAIL_ADDRESS


PR_SENDER_ENTRYID

The PR_SENDER_ENTRYID property contains the message sender's entry identifier.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0C19
Property type: | PT_BINARY
Property tag: | 0x0C190102
Corresponding X.400 attribute: | IM_ORIGINATOR

Remarks

The PR_SENDER_ENTRYID property is one of the address properties for the message sender. It must be set by the outgoing transport provider, which should never propagate any previously existing values.

If no transport provider has supplied any sender address properties, the MAPI spooler attempts to fill them in by calling the IMAPISession::QueryIdentity method for an entry identifier. If no entry identifiers have been provided, the MAPI spooler stores in PR_SENDER_ENTRYID an identifier corresponding to the string "Unknown."

For more information on the address properties, see Base Address Properties.

See Also

Sender Properties, PR_ENTRYID, PR_SENT_REPRESENTING_ENTRYID


PR_SENDER_NAME

The PR_SENDER_NAME property contains the message sender's display name.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0C1A
Property type: | PT_TSTRING
Property tag: | 0x0C1A001E (0x0C1A001F for Unicode)
Corresponding X.400 attribute: | IM_FREE_FORM_NAME and MH_T_ORIGINATOR_NAME

Remarks

The PR_SENDER_NAME property is one of the address properties for the message sender. It must be set by the outgoing transport provider, which should never propagate any previously existing values.

If no transport provider has supplied any sender address properties, the MAPI spooler attempts to fill them in by calling the IMAPISession::QueryIdentity method for an entry identifier. If no entry identifiers have been provided, the MAPI spooler stores "Unknown" in all the sender address properties of type PT_TSTRING.

For more information on the address properties, see Base Address Properties.

See Also

Sender Properties, PR_DISPLAY_NAME, PR_SENT_REPRESENTING_NAME


PR_SENDER_SEARCH_KEY

The PR_SENDER_SEARCH_KEY property contains the message sender's search key.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0C1D
Property type: | PT_BINARY
Property tag: | 0x0C1D0102

Remarks

The PR_SENDER_SEARCH_KEY property is one of the address properties for the message sender. It must be set by the outgoing transport provider, which should never propagate any previously existing values.

If no transport provider has supplied any sender address properties, the MAPI spooler attempts to fill them in by calling the IMAPISession::QueryIdentity method for an entry identifier. If no entry identifiers have been provided, the MAPI spooler stores in PR_SENDER_SEARCH_KEY a key corresponding to the string "Unknown."

For more information on the address properties, see Base Address Properties.

See Also

Sender Properties, PR_SEARCH_KEY, PR_SENT_REPRESENTING_SEARCH_KEY


PR_SENSITIVITY

The PR_SENSITIVITY property contains a value indicating the message sender's opinion of the sensitivity of a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0036
Property type: | PT_LONG
Property tag: | 0x00360003
Corresponding X.400 attribute: | IM_SENSITIVITY

Remarks

It is recommended that message objects expose the PR_SENSITIVITY property.

This property can have exactly one of the following values:

SENSITIVITY_NONE
The message has no special sensitivity.
SENSITIVITY_PERSONAL
The message is personal.
SENSITIVITY_PRIVATE
The message is private.
SENSITIVITY_COMPANY_CONFIDENTIAL
The message is designated Company Confidential.

See Also

Criticality Properties


PR_SENT_REPRESENTING_ADDRTYPE

The PR_SENT_REPRESENTING_ADDRTYPE property contains the address type for the messaging user represented by the sender.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0064
Property type: | PT_TSTRING
Property tag: | 0x0064001E (0x0064001F for Unicode)

Remarks

The PR_SENT_REPRESENTING_ADDRTYPE property is one of the address properties for the messaging user being represented by the sender. When a client application sends a message on behalf of another client, it should set all the represented sender properties to the values for that client. A messaging user sending on its own behalf typically leaves the represented sender properties unset.

The outgoing transport provider must always leave PR_SENT_REPRESENTING_ADDRTYPE unchanged if it has been set by the sending client. If it is unset, the transport provider should set it to PR_SENDER_ADDRTYPE on the outbound copy of the message, and leave it unset on the local copy.

For more information on the address properties, see Base Address Properties.

See Also

Represented Sender Properties, PR_ADDRTYPE


PR_SENT_REPRESENTING_EMAIL_ADDRESS

The PR_SENT_REPRESENTING_EMAIL_ADDRESS property contains the e-mail address for the messaging user represented by the sender.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0065
Property type: | PT_TSTRING
Property tag: | 0x0065001E (0x0065001F for Unicode)

Remarks

The PR_SENT_REPRESENTING_EMAIL_ADDRESS property is one of the address properties for the messaging user being represented by the sender. When a client application sends a message on behalf of another client, it should set all the represented sender properties to the values for that client. A messaging user sending on its own behalf typically leaves the represented sender properties unset.

The outgoing transport provider must always leave PR_SENT_REPRESENTING_EMAIL_ADDRESS unchanged if it has been set by the sending client. If it is unset, the transport provider should set it to PR_SENDER_EMAIL_ADDRESS on the outbound copy of the message, and leave it unset on the local copy.

For more information on the address properties, see Base Address Properties.

See Also

Represented Sender Properties, PR_EMAIL_ADDRESS


PR_SENT_REPRESENTING_ENTRYID

The PR_SENT_REPRESENTING_ENTRYID property contains the entry identifier for the messaging user represented by the sender.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0041
Property type: | PT_BINARY
Property tag: | 0x00410102

Remarks

The PR_SENT_REPRESENTING_ENTRYID property is one of the address properties for the messaging user being represented by the sender. When a client application sends a message on behalf of another client, it should set all the represented sender properties to the values for that client. A messaging user sending on its own behalf typically leaves the represented sender properties unset.

The outgoing transport provider must always leave PR_SENT_REPRESENTING_ENTRYID unchanged if it has been set by the sending client. If it is unset, the transport provider should set it to PR_SENDER_ENTRYID on the outbound copy of the message, and leave it unset on the local copy.

For more information on the address properties, see Base Address Properties.

See Also

Represented Sender Properties, PR_ENTRYID


PR_SENT_REPRESENTING_NAME

The PR_SENT_REPRESENTING_NAME property contains the display name for the messaging user represented by the sender.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0042
Property type: | PT_TSTRING
Property tag: | 0x0042001E (0x0042001F for Unicode)

Remarks

The PR_SENT_REPRESENTING_NAME property is one of the address properties for the messaging user being represented by the sender. When a client application sends a message on behalf of another client, it should set all the represented sender properties to the values for that client. A messaging user sending on its own behalf typically leaves the represented sender properties unset.

The outgoing transport provider must always leave PR_SENT_REPRESENTING_NAME unchanged if it has been set by the sending client. If it is unset, the transport provider should set it to PR_SENDER_NAME on the outbound copy of the message, and leave it unset on the local copy.

For more information on the address properties, see Base Address Properties.

See Also

Represented Sender Properties, PR_DISPLAY_NAME


PR_SENT_REPRESENTING_SEARCH_KEY

The PR_SENT_REPRESENTING_SEARCH_KEY property contains the search key for the messaging user represented by the sender.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x003B
Property type: | PT_BINARY
Property tag: | 0x003B0102

Remarks

The PR_SENT_REPRESENTING_SEARCH_KEY property is one of the address properties for the messaging user being represented by the sender. When a client application sends a message on behalf of another client, it should set all the represented sender properties to the values for that client. A messaging user sending on its own behalf typically leaves the represented sender properties unset.

The outgoing transport provider must always leave PR_SENT_REPRESENTING_SEARCH_KEY unchanged if it has been set by the sending client. If it is unset, the transport provider should set it to PR_SENDER_SEARCH_KEY on the outbound copy of the message, and leave it unset on the local copy.

For more information on the address properties, see Base Address Properties.

See Also

Represented Sender Properties, PR_SEARCH_KEY


PR_SENTMAIL_ENTRYID

The PR_SENTMAIL_ENTRYID property contains the entry identifier of the folder where the message should be moved after submission.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0E0A
Property type: | PT_BINARY
Property tag: | 0x0E0A0102

Remarks

The PR_SENTMAIL_ENTRYID property is often copied from the PR_IPM_SENTMAIL_ENTRYID property, the client application's standard Sent Items folder.

The client application uses PR_SENTMAIL_ENTRYID with the PR_DELETE_AFTER_SUBMIT property to control what happens to a message after it is submitted. Either one or the other should be set, but not both.

See Also

IPM Properties


PR_SERVICE_DELETE_FILES

The PR_SERVICE_DELETE_FILES property contains a list of filenames that are to be deleted when the message service is uninstalled.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Profile section objects
Identifier: | 0x3D10
Property type: | PT_MV_TSTRING
Property tag: | 0x3D10101E (0x3D10101F for Unicode)

Remarks

The filenames in the list contained in the PR_SERVICE_DELETE_FILES property are deleted from the computer when using the control panel to uninstall the message service. Do not include in the list any DLL that supports multiple message services, or additional message services could be inadvertently removed.

MAPI works only with filenames, and other strings passed to it, in the ANSI character set. Applications that use filenames in an OEM character set must convert them to ANSI before calling MAPI.

See Also

Message Service Properties


PR_SERVICE_DLL_NAME

The PR_SERVICE_DLL_NAME property contains the filename of the DLL containing the message service provider entry point function to call for configuration.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Profile section objects
Must be a column in: | Message service tables
Identifier: | 0x3D0A
Property type: | PT_TSTRING
Property tag: | 0x3D0A001E (0x3D0A001F for Unicode)

Remarks

When the entry point function name appears in the PR_SERVICE_ENTRY_NAME method, it indicates that the entry point exists.

MAPI uses a DLL file naming convention. The base filename contains up to six characters that uniquely identify the DLL. MAPI appends the string 32 to the base DLL name to identify the version that runs on 32-bit platforms. For example, when the name MAPI.DLL is specified, MAPI constructs the name MAPI32.DLL to represent the corresponding 32-bit version of the DLL.

The PR_SERVICE_DLL_NAME property should specify the base name. MAPI appends the string 32 as appropriate. Including the string 32 as part of the PR_SERVICE_DLL_NAME property results in an error.

See Also

Message Service Properties, PR_PROVIDER_DLL_NAME


PR_SERVICE_ENTRY_NAME

The PR_SERVICE_ENTRY_NAME property contains the name of the entry point function for configuration of a message service.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Profile section objects
Must be a column in: | Message service tables
Identifier: | 0x3D0B
Property type: | PT_STRING8
Property tag: | 0x3D0B001E

Remarks

It is recommended that message service implementers provide a message service entry point, but the entry point is not required. However, the entry point should be supplied only if the related configuration properties exist. If these properties do not exist, MAPI assumes that no entry point is provided.

The DLL in which the entry point function appears is named by the PR_SERVICE_DLL_NAME property.

For more information on message service entry points, see Implementing a Service Provider Entry Point Function.

See Also

Message Service Properties


PR_SERVICE_EXTRA_UIDS

The PR_SERVICE_EXTRA_UIDS property contains a list of MAPIUID structures that identify additional profile sections for the message service.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Profile section objects
Identifier: | 0x3D0D
Property type: | PT_BINARY
Property tag: | 0x3D0D0102

Remarks

New profile sections can be created for each message filter. When the information about the message service is to be copied to another profile, it is important to copy the additional profile sections for the filters as well. A service provider that uses additional profile sections can store the MAPIUID structures of those profile sections in PR_SERVICE_EXTRA_UIDS, allowing MAPI to copy the additional message service information.

See Also

Message Service Properties


PR_SERVICE_NAME

The PR_SERVICE_NAME property contains the name of a message service as set by the user in the MAPISVC.INF file.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Profile section objects
Must be a column in: | Message service tables
Identifier: | 0x3D09
Property type: | PT_TSTRING
Property tag: | 0x3D09001E (0x3D09001F for Unicode)

Remarks

The name contained in the PR_SERVICE_NAME property is specific to the message service. It comes from the [Services] section in MAPISVC.INF.

PR_SERVICE_NAME appears as a column in the message service table and can be used to filter services. Because it is used to identify and filter services, the value should not be localized.

See Also

Message Service Properties


PR_SERVICE_SUPPORT_FILES

The PR_SERVICE_SUPPORT_FILES property contains a list of the files that belong to the message service.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Profile section objects
Must be a column in: | Message service tables
Identifier: | 0x3D0F
Property type: | PT_MV_TSTRING
Property tag: | 0x3D0F101E (0x3D0F101F for Unicode)

Remarks

Using a dialog box in the control panel applet, a user can obtain the list of files that belong to the message service. For example, the user can obtain the names of all DLLs that belong to the service. The user can then seek additional details about the specified files, such as the names and version numbers of all the DLLs. MAPI uses the PR_SERVICE_SUPPORT_FILES property to create a support file list in a dialog box for messaging user selection.

MAPI works only with filenames, and other strings passed to it, in the ANSI character set. Client applications that use filenames in an OEM character set must convert them to ANSI before calling MAPI.

See Also

Message Service Properties


PR_SERVICE_UID

The PR_SERVICE_UID property contains the MAPIUID structure for a message service.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Profile section objects
Must be a column in: | Message service tables
Identifier: | 0x3D0C
Property type: | PT_BINARY
Property tag: | 0x3D0C0102

Remarks

The PR_SERVICE_UID property is computed by MAPI on profile section objects. MAPI uses this property to group all the providers that belong to the same message service. PR_SERVICE_UID is supplied as a parameter to most of the IMsgServiceAdmin methods. It must not appear in MAPISVC.INF.

See Also

Message Service Properties, IMsgServiceAdmin::IUnknown


PR_SERVICES

The PR_SERVICES property contains a list of identifiers of message services in the current profile.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3D0E
Property type: | PT_BINARY
Property tag: | 0x3D0E0102

Remarks

Do not use this property. It is reserved for use by MAPI.

See Also

Reserved Properties, MAPIUID


PR_SPOOLER_STATUS

The PR_SPOOLER_STATUS property contains the status of the message based on information available to the MAPI spooler.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects
Identifier: | 0x0E10
Property type: | PT_LONG
Property tag: | 0x0E100003

Remarks

The PR_SPOOLER_STATUS property is computed by MAPI on message objects.

This property appears on inbound messages only and is reserved in all other cases. It indicates whether or not a message has been delivered to its final location or whether a messaging hook provider potentially deleted the message while rerouting it.

Client applications should never set this property. For an inbound message, a client or service provider can call the IMAPIProp::GetProps property on PR_SPOOLER_STATUS to determine the message status. The value S_OK indicates that the message was successfully delivered to the message store. The value MAPI_E_OBJECT_DELETED indicates that the message was deleted and was never committed to the store.

Message store providers should support PR_SPOOLER_STATUS on messages, recipient tables, and the outgoing queue table. Clients and providers should be able to set columns on the outgoing queue table and restrict based on this property.


PR_START_DATE

The PR_START_DATE property contains the starting date and time of an appointment as managed by a scheduling application.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message objects used for scheduling
Identifier: | 0x0060
Property type: | PT_SYSTIME
Property tag: | 0x00600040

Remarks

Scheduling applications should set both the PR_START_DATE and PR_END_DATE properties when sending meeting requests.

See Also

Schedule Properties


PR_STATE_OR_PROVINCE

The PR_STATE_OR_PROVINCE property contains the name of the recipient's state or province.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A28
Property type: | PT_TSTRING
Property tag: | 0x3A28001E (0x3A28001F for Unicode)

Remarks

The PR_STATE_OR_PROVINCE property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_STATUS

The PR_STATUS property contains a 32-bit bitmask of flags defining folder status.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Folder objects
Must be a column in: | Hierarchy tables
Identifier: | 0x360B
Property type: | PT_LONG
Property tag: | 0x360B0003

Remarks

The PR_STATUS property for folders is analogous to the PR_MSG_STATUS property for messages. Its flags are provided for the client application only and do not affect the message store. Clients can use or ignore these settings. The client can also define its own values for the client-definable bits of the PR_STATUS property.

One or more of the following flags can be set for the PR_STATUS bitmask:

FLDSTATUS_DELMARKED
The folder is marked for deletion. The client application sets this flag.
FLDSTATUS_HIDDEN
The folder is hidden.
FLDSTATUS_HIGHLIGHTED
The folder is highlighted, for example, shown in reverse video.
FLDSTATUS_TAGGED
The folder is tagged.

Message store providers set a folder's PR_STATUS property to one or more of these values and clients interpret the status as appropriate for their applications. For example, a client can use the folder status to visually differentiate between folders in a hierarchy table, displaying folders with the same status in the same way. Highlighted folders can be shown in reverse videa, tagged folders and folders marked for deletion can be shown with a meaningful icon, and hidden folders can be concealed.

Bits 16 through 31 (0x10000 through 0x80000000) of PR_STATUS are available for use by the IPM client application. All other bits are reserved for use by MAPI; those not defined in the preceding list should be initially set to zero and not altered subsequently.

See Also

Folder Properties


PR_STATUS_CODE

The PR_STATUS_CODE property contains a bitmask of flags indicating the current status of a session resource. All service providers set status codes as does MAPI to report on the status of the subsystem, the MAPI spooler, and the integrated address book.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Status objects
Must be a column in: | Status tables
Identifier: | 0x3E04
Property type: | PT_LONG
Property tag: | 0x3E040003

Remarks

The status code must appear in the MAPISVC.INF file for all providers.

Status objects are implemented by MAPI and by all service providers. There are two sets of valid values for status codes, one set for all status objects and another set for transport providers only. All status objects can set PR_STATUS_CODE to the following values:

STATUS_AVAILABLE
Indicates that the resource is operational.
STATUS_FAILURE
Indicates that the resource is experiencing a problem. For service providers, STATUS_FAILURE indicates that the provider might soon be shut down to end the current session.
STATUS_OFFLINE
Indicates that only local data or services are available.

Transport providers can also set their status objects' PR_STATUS_CODE properties to the following values:

STATUS_INBOUND_ACTIVE
Indicates that the transport provider is receiving an inbound message.
STATUS_INBOUND_ENABLED
Indicates that the transport provider is able to receive inbound messages.
STATUS_INBOUND_FLUSH
Indicates that the transport provider is downloading messages from the inbound queue.
STATUS_OUTBOUND_ACTIVE
Indicates that the transport provider is receiving an outbound message.
STATUS_OUTBOUND_ENABLED
Indicates that the transport provider is able to handle outbound messages.
STATUS_OUTBOUND_FLUSH
Indicates that the transport provider is uploading messages from its outbound queue.
STATUS_REMOTE_ACCESS
Indicates that the transport provider supports remote access.

See Also

Provider Properties, PR_STATUS_STRING


PR_STATUS_STRING

The PR_STATUS_STRING property contains an ASCII message indicating the current status of a session resource.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Status objects
Identifier: | 0x3E08
Property type: | PT_TSTRING
Property tag: | 0x3E08001E (0x3E08001F for Unicode)

Remarks

The PR_STATUS_STRING property gives service providers and MAPI the opportunity to supply specific information about the status of a session resource, such as the integrated address book or a particular service provider. The PR_STATUS_STRING property explains and provides additional information about a status code, or PR_STATUS_CODE property. Whereas PR_STATUS_CODE is required for all status objects, PR_STATUS_STRING is optional. When the transport provider does not supply a value, the MAPI spooler supplies a default value.

The string is generated on the same side of the remote procedure call as the MAPI spooler; it travels through shared memory rather than being marshaled across a process boundary.

See Also

Provider Properties, PR_STATUS_CODE


PR_STORE_ENTRYID

The PR_STORE_ENTRYID property contains the unique entry identifier of the message store in which an object resides.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Folder, message, and message store objects
Identifier: | 0x0FFB
Property type: | PT_BINARY
Property tag: | 0x0FFB0102

Remarks

The PR_STORE_ENTRYID property is used to open a message store with the IMAPISession::OpenMsgStore method. It is also used to open any object owned by the message store.

For a message store, this property is identical to the store's own PR_ENTRYID property. A client application can compare the two properties using the IMAPISession::CompareEntryIDs method.

See Also

Provider Properties


PR_STORE_PROVIDERS

The PR_STORE_PROVIDERS property contains a list of identifiers of message store providers in the current profile.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3D00
Property type: | PT_BINARY
Property tag: | 0x3D000102

Remarks

Do not use this property. It is reserved for use by MAPI.

See Also

Reserved Properties, MAPIUID


PR_STORE_RECORD_KEY

The PR_STORE_RECORD_KEY property contains the unique binary-comparable identifier (record key) of the message store in which an object resides.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Folder, message, and message store objects
Identifier: | 0x0FFA
Property type: | PT_BINARY
Property tag: | 0x0FFA0102

Remarks

For a message store, the PR_STORE_RECORD_KEY property is identical to the store's own PR_RECORD_KEY property.

The relationship between PR_STORE_RECORD_KEY and PR_RECORD_KEY is the same as the relationship between PR_STORE_ENTRYID and PR_ENTRYID.

See Also

Provider Properties


PR_STORE_STATE

The PR_STORE_STATE property contains a flag that describes the state of the message store.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message store objects
Identifier: | 0x340E
Property type: | PT_LONG
Property tag: | 0x340E0003

Remarks

The PR_STORE_STATE property is dynamic and can change based on user actions, unlike the PR_STORE_SUPPORT_MASK property.

The following value can be set:

STORE_HAS_SEARCHES
The user has created one or more active searches in the store.

See Also

Provider Properties, PR_STORE_ENTRYID


PR_STORE_SUPPORT_MASK

The PR_STORE_SUPPORT_MASK property contains a bitmask of flags that client applications should query to determine the characteristics of a message store.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Folder, message, and message store objects
Identifier: | 0x3A0D
Property type: | PT_LONG
Property tag: | 0x3A0D0003

Remarks

The PR_STORE_SUPPORT_MASK property discloses the capabilities of a message store to client applications planning to send it a message. The flags can facilitate decisions by a client or another store, such as whether to send PR_BODY or only PR_RTF_COMPRESSED. A client should never set PR_STORE_SUPPORT_MASK; an attempt returns MAPI_E_COMPUTED.

One or more of the following flags can be set for the PR_STORE_SUPPORT_MASK bitmask:

STORE_ATTACH_OK
The message store supports attachments (OLE or non-OLE) to messages.
STORE_CATEGORIZE_OK
The message store supports categorized views of tables.
STORE_CREATE_OK
The message store supports creation of new messages.
STORE_ENTRYID_UNIQUE
Entry identifiers for the objects in the message store are unique, that is, never reused during the life of the store.
STORE_HTML_OK
The message store supports Hypertext Markup Language (HTML) messages, stored in the PR_BODY_HTML property.
STORE_MODIFY_OK
The message store supports modification of its existing messages.
STORE_MV_PROPS_OK
The message store supports multivalued properties, guarantees the stability of value order in a multivalued property throughout a save operation, and supports instantiation of multivalued properties in tables.
STORE_NOTIFY_OK
The message store supports notifications.
STORE_OLE_OK
The message store supports OLE attachments. The OLE data is accessible through an IStorage interface, such as that available through the PR_ATTACH_DATA_OBJ property.
STORE_PUBLIC_FOLDERS
The folders in this store are public (multi-user), not private (possibly multi-instance but not multi-user).
STORE_READONLY
All interfaces for the message store have a read-only access level.
STORE_RESTRICTION_OK
The message store supports restrictions.
STORE_RTF_OK
The message store supports Rich Text Format (RTF) messages, usually stored compressed, and the store itself keeps PR_BODY and PR_RTF_COMPRESSED synchronized.
STORE_SEARCH_OK
The message store supports search-results folders.
STORE_SORT_OK
The message store supports sorting views of tables.
STORE_SUBMIT_OK
The message store supports marking a message for submission.
STORE_UNCOMPRESSED_RTF
The message store supports storage of Rich Text Format (RTF) messages in uncompressed form. An uncompressed RTF stream is identified by the value dwMagicUncompressedRTF in the stream header. The dwMagicUncompressedRTF value is defined in the RTFLIB.H file.

An RTF version of a message can always be stored, even if the message store is non-RTF-aware. If the STORE_RTF_OK bit is not set for a particular store, a client maintaining RTF versions must itself call the RTFSync function to keep the PR_BODY and PR_RTF_COMPRESSED versions synchronized for text content. RTF is always stored in PR_RTF_COMPRESSED, whether it is actually compressed or not.

See Also

Provider Properties


PR_STREET_ADDRESS

The PR_STREET_ADDRESS property contains the recipient's street address.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A29
Property type: | PT_TSTRING
Property tag: | 0x3A29001E (0x3A29001F for Unicode)

Remarks

The PR_STREET_ADDRESS property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_SUBFOLDERS

The PR_SUBFOLDERS property contains TRUE if a folder contains subfolders.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | All folders
Identifier: | 0x360A
Property type: | PT_BOOLEAN
Property tag: | 0x360A000B

Remarks

Message stores must compute the PR_SUBFOLDERS property for all folders.

See Also

Folder Properties, PR_FOLDER_TYPE


PR_SUBJECT

The PR_SUBJECT property contains the full subject of a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x0037
Property type: | PT_TSTRING
Property tag: | 0x0037001E (0x0037001F for Unicode)
Corresponding X.400 attribute: | IM_SUBJECT

Remarks

The PR_SUBJECT property is recommended on all message objects.

This property is always the full subject text, that is, the concatenation of the prefix and the normalized subject. If there is no prefix, the normalized subject should be the same as the subject. A message store or transport provider uses both the PR_SUBJECT and PR_SUBJECT_PREFIX properties to compute the normalized subject using the rule described under PR_NORMALIZED_SUBJECT.

The subject properties are typically small strings of fewer than 256 characters, and a message store provider is not obligated to support the OLE IStream interface on them. The client should always attempt access through the IMAPIProp interface first, and resort to IStream only if MAPI_E_NOT_ENOUGH_MEMORY is returned.

For a report, PR_SUBJECT contains the original message's subject preceded by a string indicating what has happened to the message.

See Also

Subject Properties


PR_SUBJECT_IPM

The PR_SUBJECT_IPM property contains a binary value that is copied from the message for which a report is being generated.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Report message objects
Identifier: | 0x0038
Property type: | PT_BINARY
Property tag: | 0x00380102
Corresponding X.400 attribute: | IM_SUBJECT

Remarks

The PR_SUBJECT_IPM property, like the PR_REPORT_TAG property, can be used to correlate a report with the original message. The PR_PARENT_KEY property can also be used for correlation.

See Also

Report Properties


PR_SUBJECT_PREFIX

The PR_SUBJECT_PREFIX property contains a subject prefix that typically indicates some action on a message, such as "FW: " for forwarding.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x003D
Property type: | PT_TSTRING
Property tag: | 0x003D001E (0x003D001F for Unicode)

Remarks

The PR_SUBJECT_PREFIX property is recommended on all message objects.

The subject prefix consists of one or more alphanumeric characters, followed by a colon and a space (which are part of the prefix). It must not contain any nonalphanumeric characters before the colon. Absence of a prefix can be represented by an empty string or by PR_SUBJECT_PREFIX not being set.

If PR_SUBJECT_PREFIX is set explicitly, it can be of any length and use any alphanumeric characters, but it must match a substring at the beginning of the PR_SUBJECT property. If PR_SUBJECT_PREFIX is not set by the sender and must be computed, its contents are more restricted. The rule for computing the prefix is that PR_SUBJECT must begin with one, two, or three letters (alphabetic only) followed by a colon and a space. If such a substring is found at the beginning of PR_SUBJECT, it then becomes PR_SUBJECT_PREFIX (and also stays at the beginning of PR_SUBJECT). Otherwise PR_SUBJECT_PREFIX remains unset.

PR_SUBJECT_PREFIX and PR_NORMALIZED_SUBJECT should be computed as part of the IMAPIProp::SaveChanges implementation. A client should not prompt IMAPIProp::GetProps for their values until they have been committed by an IMAPIProp::SaveChanges call.

The subject properties are typically small strings of fewer than 256 characters, and a message store provider is not obligated to support the OLE IStream interface on them. A client should always attempt access through the IMAPIProp interface first, and resort to IStream only if MAPI_E_NOT_ENOUGH_MEMORY is returned.

See Also

Subject Properties


PR_SUBMIT_FLAGS

The PR_SUBMIT_FLAGS property contains a bitmask of flags indicating details about a message submission.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | Outgoing queue tables
Identifier: | 0x0E14
Property type: | PT_LONG
Property tag: | 0x0E140003

Remarks

One or more of the following flags can be set for the PR_SUBMIT_FLAGS bitmask:

SUBMITFLAG_LOCKED
The MAPI spooler currently has the message locked.
SUBMITFLAG_PREPROCESS
The message needs preprocessing. When the MAPI spooler is done preprocessing this message, it should call the IMessage::SubmitMessage method. The message store provider recognizes that the spooler, rather than the client application, has called SubmitMessage, clears the flag, and continues message submission.

See Also

IMsgStore::SetLockState


PR_SUPPLEMENTARY_INFO

The PR_SUPPLEMENTARY_INFO property contains additional information for use in a report.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects used for reports
Identifier: | 0x0C1B
Property type: | PT_TSTRING
Property tag: | 0x0C1B001E (0x0C1B001F for Unicode)
Corresponding X.400 attribute: | IM_SUPPLEMENTARY_INFO

Remarks

The PR_SUPPLEMENTARY_INFO property contains information generated by the message transfer agent or transport provider related to the report. It is typically used for delivery or nondelivery report text that originated with the underlying messaging system.

See Also

Report Properties


PR_SURNAME

The PR_SURNAME property contains the recipient's family name.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A11
Property type: | PT_TSTRING
Property tag: | 0x3A11001E (0x3A11001F for Unicode)

Remarks

The PR_SURNAME property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_TELEX_NUMBER

The PR_TELEX_NUMBER property contains the recipient's telex number.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A2C
Property type: | PT_TSTRING
Property tag: | 0x3A2C001E (0x3A2C001F for Unicode)

Remarks

The PR_TELEX_NUMBER property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

See Also

Personal Information Properties


PR_TEMPLATEID

The PR_TEMPLATEID property contains an entry identifier that can find the code associated with a service provider.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Address book provider objects
Identifier: | 0x3902
Property type: | PT_BINARY
Property tag: | 0x39020102

Remarks

The entry identifier can bind the code to the data.

See Also

IABLogon::OpenTemplateID, IMAPISupport::OpenTemplateID


PR_TITLE

The PR_TITLE property contains the recipient's job title.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A17
Property type: | PT_TSTRING
Property tag: | 0x3A17001E (0x3A17001F for Unicode)

Remarks

The PR_TITLE property is one of the properties that provide identification and access information for a recipient. These properties are defined by the recipient and the recipient's organization. For more information on this group of properties, see IMailUser::IMAPIProp.

PR_TITLE is commonly used to indicate the recipient's formal job title, such as Senior Programmer, rather than occupational class, such as programmer. It is not typically used for "suffix" titles such as Esq. or DDS.

Common PR_TITLE values include: Managing Director, Programmer II, Associate Professor, and Development Lead.

See Also

Personal Information Properties


PR_TNEF_CORRELATION_KEY

The PR_TNEF_CORRELATION_KEY property contains a value used to correlate a TNEF attachment with a message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | TNEF attachment subobjects
Identifier: | 0x007F
Property type: | PT_BINARY
Property tag: | 0x007F0102

Remarks

It is recommended that TNEF attachment subobjects expose the PR_TNEF_CORRELATION_KEY property. This property determines whether or not an inbound TNEF file belongs to the message it is attached to. It is used primarily by transport providers and gateways.

On an outbound message, the transport provider should compute a binary value unique to that message, or use an existing value that satisfies the uniqueness requirement, such as a message identifier. The transport provider should store this value in PR_TNEF_CORRELATION_KEY and then call the ITnef::AddProps method to encapsulate it. The same value should also be stored in the transport envelope in a place defined by the provider, such as the message header.

On an inbound message, the transport provider should call the ITnef::ExtractProps method to decapsulate the TNEF attachment and then compare PR_TNEF_CORRELATION_KEY with the value stored in the transport envelope. If the values match, TNEF should be processed normally, that is, all the properties extracted from the TNEF attachment should be used. If the values do not match, all the properties from the TNEF attachment should be ignored. If PR_TNEF_CORRELATION_KEY is not set, the TNEF file should be considered to belong to this message, and the other properties extracted from it should be used.

See Also

Attachment Properties


PR_TRANSMITTABLE_DISPLAY_NAME

The PR_TRANSMITTABLE_DISPLAY_NAME property contains a recipient's display name in a secure form that cannot be changed.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Messaging user objects
Identifier: | 0x3a20
Property type: | PT_TSTRING
Property tag: | 0x3A20001E (0x3A20001F for Unicode)

Remarks

The PR_TRANSMITTABLE_DISPLAY_NAME property should be furnished by all address book providers. It contains the version of the recipient's display name that is transmitted with the message. For most address book providers this property has the same value as the PR_DISPLAY_NAME property. Providers that do not have a secure display name return PT_ERROR and MAPI changes the display name by adding quotation marks around the name.

A client application can use PR_TRANSMITTABLE_DISPLAY_NAME to prevent alteration or "spoofing" of entries. An example of spoofing is transmitting John Doe as John (What a Guy) Doe.

This property was formerly defined as PR_TRANSMITABLE_DISPLAY_NAME.

See Also

Supplemental Name Properties


PR_TRANSPORT_KEY

The PR_TRANSPORT_KEY property contains a value used by the MAPI spooler to track the progress of an outbound message through the outgoing transport providers.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x0E16
Property type: | PT_LONG
Property tag: | 0x0E160003

Remarks

Do not use this property. It is reserved for use by MAPI.

See Also

Reserved Properties, PR_TRANSPORT_PROVIDERS


PR_TRANSPORT_MESSAGE_HEADERS

The PR_TRANSPORT_MESSAGE_HEADERS property contains transport-specific message envelope information.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x007D
Property type: | PT_TSTRING
Property tag: | 0x007D001E (0x007D001F for Unicode)

Remarks

The transport provider can generate the message header information for inbound messages.

The PR_TRANSPORT_MESSAGE_HEADERS property offers an alternative to either discarding the transport message header information or prepending it to the message text. The client can choose whether or not to display the information.

See Also

Message Properties, PR_BODY


PR_TRANSPORT_PROVIDERS

The PR_TRANSPORT_PROVIDERS property contains a list of identifiers of transport providers in the current profile.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3D02
Property type: | PT_BINARY
Property tag: | 0x3D020102

Remarks

Do not use this property. It is reserved for use by MAPI.

See Also

Reserved Properties, MAPIUID


PR_TRANSPORT_STATUS

Obsolete MAPI spooler property.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x0E11
Property type: | PT_LONG
Property tag: | 0x0E110003

Remarks

Do not use this property.

See Also

Unused Properties


PR_TYPE_OF_MTS_USER

The PR_TYPE_OF_MTS_USER property contains the type of a message recipient, for use in a report.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Recipient subobjects within report message objects
Identifier: | 0x0C1C
Property type: | PT_LONG
Property tag: | 0x0C1C0003
Corresponding X.400 attribute: | MH_T_DELIVERY_POINT

See Also

Report Properties, PR_CORRELATE_MTSID


PR_USER_CERTIFICATE

The PR_USER_CERTIFICATE property contains an ASN.1 authentication certificate for a messaging user.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A22
Property type: | PT_BINARY
Property tag: | 0x3A220102

Remarks

An authentication certificate is similar to a digital signature. Several MAPI properties supply ASN.1 certificates.

See Also

Certificate Properties


PR_USER_X509_CERTIFICATE

The PR_USER_X509_CERTIFICATE property contains X.509 version 3 security certificates for a messaging user.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Messaging user objects
Identifier: | 0x3A70
Property type: | PT_MV_BINARY
Property tag: | 0x3A701102

Remarks

The PR_USER_X509_CERTIFICATE property is used by applications that utilize public-key security. It holds a binary representation of one or more X.509 version 3 security certificates.

Various applications and clients can use this property for their own security certificates. The binary format of the X.509 data can vary among vendors.

See Also

Certificate Properties


PR_VALID_FOLDER_MASK

The PR_VALID_FOLDER_MASK property contains a bitmask of flags that indicate the validity of the entry identifiers of the folders in a message store.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message store objects
Identifier: | 0x35DF
Property type: | PT_LONG
Property tag: | 0x35DF0003

Remarks

A folder's entry identifier can become invalid if a user deletes the folder or if the message store becomes corrupted.

One or more of the following flags can be set for the PR_VALID_FOLDER_MASK bitmask:

FOLDER_COMMON_VIEWS_VALID
The common views folder has a valid entry identifier. See PR_COMMON_VIEWS_ENTRYID.
FOLDER_FINDER_VALID
The finder folder has a valid entry identifier. See PR_FINDER_ENTRYID.
FOLDER_IPM_INBOX_VALID
The interpersonal message (IPM) receive folder has a valid entry identifier. See IMsgStore::GetReceiveFolder.
FOLDER_IPM_OUTBOX_VALID
The IPM Outbox folder has a valid entry identifier. See PR_IPM_OUTBOX_ENTRYID.
FOLDER_IPM_SENTMAIL_VALID
The IPM Sent Items folder has a valid entry identifier. See PR_IPM_SENTMAIL_ENTRYID.
FOLDER_IPM_SUBTREE_VALID
The IPM folder subtree has a valid entry identifier. See PR_IPM_SUBTREE_ENTRYID.
FOLDER_IPM_WASTEBASKET_VALID
The IPM Deleted Items folder has a valid entry identifier. See PR_IPM_WASTEBASKET_ENTRYID.
FOLDER_VIEWS_VALID
The views folder has a valid entry identifier. See PR_VIEWS_ENTRYID.

For more information on folder entry identifiers, see Opening a Folder.

See Also

Folder Properties, PR_FOLDER_TYPE


PR_VIEWS_ENTRYID

The PR_VIEWS_ENTRYID property contains the entry identifier of the user-defined Views folder.

Quick Info

Header file: | MAPITAGS.H
Must be exposed by: | Message store objects
Identifier: | 0x35E5
Property type: | PT_BINARY
Property tag: | 0x35E50102

Remarks

The common view folder contains a predefined set of standard view specifiers, while the view folder contains specifiers defined by a messaging user. These folders, which are not visible in the interpersonal message (IPM) hierarchy, can hold many view specifiers, each one stored as a message. The client application can choose to merge the two sets of specifiers and make them both available.

For more information on views, see View Folders.

See Also

Folder Properties, PR_COMMON_VIEWS_ENTRYID, PR_DEFAULT_VIEW_ENTRYID


PR_WIZARD_NO_PAB_PAGE

The PR_WIZARD_NO_PAB_PAGE property contains TRUE if the Profile Wizard is to suppress the PAB page.

Quick Info

Header file: | MAPIWZ.H
May be exposed by: | Provider objects
Identifier: | 0x6701
Property type: | PT_BOOLEAN
Property tag: | 0x6701000B

Remarks

Service providers can set this property when calling a function based on the LAUNCHWIZARDENTRY function prototype. PR_WIZARD_NO_PAB_PAGE tells the Profile Wizard that the provider does not want the personal address book (PAB) page to be displayed during the user dialog.

See Also

Provider Properties


PR_WIZARD_NO_PST_PAGE

The PR_WIZARD_NO_PST_PAGE property contains TRUE if the Profile Wizard is to suppress the PST page.

Quick Info

Header file: | MAPIWZ.H
May be exposed by: | Provider objects
Identifier: | 0x6700
Property type: | PT_BOOLEAN
Property tag: | 0x6700000B

Remarks

Service providers can set this property when calling a function based on the LAUNCHWIZARDENTRY function prototype. PR_WIZARD_NO_PST_PAGE tells the Profile Wizard that the provider does not want the personal message store (PST) page to be displayed during the user dialog.

See Also

Provider Properties


PR_X400_CONTENT_TYPE

The PR_X400_CONTENT_TYPE property contains the content type for a submitted message.

Quick Info

Header file: | MAPITAGS.H
May be exposed by: | Message objects
Identifier: | 0x003C
Property type: | PT_BINARY
Property tag: | 0x003C0102
Corresponding X.400 attribute: | MH_T_CONTENT_TYPE

See Also

Message Properties, PR_X400_DEFERRED_DELIVERY_CANCEL


PR_X400_DEFERRED_DELIVERY_CANCEL

The PR_X400_DEFERRED_DELIVERY_CANCEL property was originally meant to contain TRUE if the message transfer system (MTS) allows X.400 deferred delivery cancellation.

Quick Info

Header file: | MAPITAGS.H
Identifier: | 0x3E09
Property type: | PT_BOOLEAN
Property tag: | 0x3E09000B

Remarks

Do not use this property. It is not supported in MAPI 1.0.

See Also

Unused Properties, PR_X400_CONTENT_TYPE


PR_XPOS

The PR_XPOS property contains the x coordinate of the starting position (the upper-left corner) of a dialog box control, in standard Windows dialog units.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | Display tables
Identifier: | 0x3F05
Property type: | PT_LONG
Property tag: | 0x3F050003

Remarks

The PR_XPOS, PR_YPOS, PR_DELTAX, and PR_DELTAY properties position and size the dialog box control.

See Also

Dialog Box Control Properties


PR_YPOS

The PR_YPOS property contains the y coordinate of the starting position (the upper-left corner) of a dialog box control, in standard Windows dialog units.

Quick Info

Header file: | MAPITAGS.H
Must be a column in: | Display tables
Identifier: | 0x3F06
Property type: | PT_LONG
Property tag: | 0x3F060003

Remarks

The PR_XPOS, PR_YPOS, PR_DELTAX, and PR_DELTAY properties position and size the control.

See Also

Dialog Box Control Properties


MAPI Structures

The following alphabetized entries describe MAPI structures. For more detailed information, cross references to other publications or to other topics in this documentation are also included.


ADRENTRY

The ADRENTRY structure describes zero or more properties belonging to a recipient.

Quick Info

Header file: MAPIDEFS.H

typedef struct _ADRENTRY
{
     ULONG        ulReserved1;
     ULONG        cValues;
     LPSPropValue rgPropVals;
} ADRENTRY, FAR *LPADRENTRY;

Members

ulReserved1
Reserved; must be zero.
cValues
Count of properties in the property value array pointed to by the rgPropVals member. The cValues member can be zero.
rgPropVals
Pointer to a property value array describing the properties for the recipient. The rgPropVals member can be NULL.

Remarks

An ADRENTRY structure describes properties belonging to a single recipient. The properties that are typically used to describe a recipient include:

PR_DISPLAY_NAME

PR_ADDRTYPE

PR_EMAIL_ADDRESS

PR_ENTRYID

When an entry identifier — or PR_ENTRYID property — appears in the SPropValue array for a recipient, this indicates that the recipient has been resolved. Clients call the IAddrBook::ResolveName method to ensure that all recipients in the recipient list of an outgoing message have been resolved. Only resolved recipients can be sent with messages.

ADRENTRY structures are commonly combined to form an array for the aEntries member of an ADRLIST structure.

ADRENTRY structures and SRow structures are identical in that they both contain a reserved member, an array of property values, and a count of values in the array. Whereas ADRENTRY structures are combined to form the aEntries member of an ADRLIST structure, SRow structures are combined to form the aRow member of an SRowSet structure. Both types of structures follow the same allocation rules, implying that an SRowSet structure that is retrieved from the contents table of an address book container can be cast to an ADRLIST structure and used as is.

An ADRENTRY structure can be empty. An ADRENTRY structure contained in the ADRLIST structure pointed to by the lppAdrList parameter in a call to IAddrBook::Address can be empty when, for example, a recipient is being removed.

For more information on allocating memory for ADRENTRY structures, see Managing Memory for ADRLIST and SRowSet Structures.

See Also

Address Structures, IAddrBook::Address, IMessage::ModifyRecipients, MAPIAllocateBuffer, SRow


ADRLIST

The ADRLIST structure describes zero or more properties belonging to one or more recipients.

Quick Info

Header file: | MAPIDEFS.H
Related macros: | CbADRLIST CbNewADRLIST SizedADRLIST

typedef struct _ADRLIST
{
     ULONG      cEntries;
     ADRENTRY   aEntries[MAPI_DIM];
} ADRLIST, FAR *LPADRLIST;

Members

cEntries
Count of entries in the array specified by the aEntries member.
aEntries
Array of ADRENTRY structures, one structure for each recipient.

Remarks

An ADRLIST structure contains one or more ADRENTRY structures, each describing the properties of a recipient. A recipient can be unresolved, meaning that it is lacking an entry identifier in its array of property values, or resolved, meaning that the PR_ENTRYID property is included. Typically, resolved recipients also have an e-mail address — the PR_EMAIL_ADDRESS property. However, the e-mail address is not required. ADRLIST structures are used, for example, to describe the recipient list for an outgoing message and by MAPI to display the entries in the address book.

ADRLIST structures resemble SRowSet structures — the structures used for representing rows in tables. In fact, these two structures are designed so that they can be used interchangeably. Both contain an array of structures describing a group of properties and a count of the values in the array. Whereas in the ADRLIST structure, the array contains ADRENTRY structures, in the SRowSet structure the array contains SRow structures. ADRENTRY structures and SRow structures are identical in layout. Because ADRLIST and SRowSet structures follow the same allocation rules, an SRowSet structure that is retrieved from the contents table of an address book container can be cast to an ADRLIST structure and used as is.

The following diagram illustrates the layout of an ADRLIST structure.

The ADRENTRY and SPropValue portions in an ADRLIST structure must be allocated and freed independently of the other parts. That is, each SPropValue structure must be allocated individually after memory for the ADRENTRY structure has been allocated and freed before the ADRENTRY structure is freed. This independence in handling memory allows recipients and individual recipient properties to be freely added or deleted from the address list.

The MAPIAllocateBuffer and MAPIFreeBuffer functions must be used to allocate and free the ADRLIST structure and all its parts.

If a recipient list is too large to fit in memory, clients can call the IMessage::ModifyRecipients method to work with a subset of the list. Clients should not use the address book common dialog boxes in such a situation.

For more information on allocating memory for ADRENTRY structures, see Managing Memory for ADRLIST and SRowSet Structures.

See Also

Address Structures, ADRENTRY, CbNewADRLIST, IMessage::ModifyRecipients, SRowSet


ADRPARM

The ADRPARM structure describes the display and behavior of the common address dialog box.

Quick Info

Header file: MAPIDEFS.H

typedef struct _ADRPARM
{
     ULONG            cbABContEntryID;
     LPENTRYID        lpABContEntryID;
     ULONG            ulFlags;
     LPVOID           lpReserved;
     ULONG            ulHelpContext;
     LPTSTR           lpszHelpFileName;
     LPFNABSDI        lpfnABSDI;
     LPFNDISMISS      lpfnDismiss;
     LPVOID           lpvDismissContext;
     LPTSTR           lpszCaption;
     LPTSTR           lpszNewEntryTitle;
     LPTSTR           lpszDestWellsTitle;
     ULONG            cDestFields;
     ULONG            nDestFieldFocus;
     LPTSTR FAR      *lppszDestTitles;
     ULONG FAR       *lpulDestComps;
     LPSRestriction   lpContRestriction;
     LPSRestriction   lpHierRestriction;
} ADRPARM, FAR *LPADRPARM;

Members

cbABContEntryID
Count of bytes in the entry identifier pointed to by lpABContEntryID.
lpABContEntryID
Pointer to the entry identifier of the container that initially supplies the list of recipient addresses that are displayed in the address dialog box.
ulFlags
Bitmask of flags associated with various address dialog box options. The following flags can be set:
AB_RESOLVE
Causes all names to be resolved after the address dialog box is closed. If there are ambiguous entries resulting from the name resolution process, a dialog box is displayed to prompt the user for help in resolving them. Setting this flag guarantees that all of the names returned by IAddrBook::Address are resolved.
AB_SELECTONLY
Disables the creation of one-off addresses for a recipient list. This flag is used only if the dialog box is modal, as indicated by the DIALOG_MODAL flag being set.
ADDRESS_ONE
The user can select exactly one recipient instead of multiple recipients from a list. This flag is valid only when cDestFields is zero and the dialog box is modal, as indicated by the DIALOG_MODAL flag being set.
DIALOG_MODAL
Causes the modal version of the common address dialog box to be displayed. Either this flag or DIALOG_SDI should be set; they cannot both be set.
DIALOG_OPTIONS
Causes the Send Options button to be displayed on the dialog box. This flag is used only if the dialog box is modal, as indicated by the DIALOG_MODAL flag being set.
DIALOG_SDI
Causes the modeless version of the common address dialog box to be displayed. Either this flag or DIALOG_MODAL should be set; they cannot both be set.
lpReserved
Reserved, must be zero.
ulHelpContext
Specifies the context within Help that will first be shown when the user clicks the Help button in the address dialog box.
lpszHelpFileName
Pointer to the name of a Help file that will be associated with the address dialog box. The lpszHelpFileName member is used in conjunction with ulHelpContext to call the Windows WinHelp function.
lpfnABSDI
Pointer to a MAPI function based on the ACCELERATEABSDI prototype or NULL. This member applies to the modeless version of the dialog box only, as indicated by the DIALOG_SDI flag being set.

Clients building an ADRPARM structure to pass to IAddrBook::Address must always set the lpfnABSDI member to NULL. If the DIALOG_SDI flag is set, MAPI will then set it to a valid function before returning. Clients call this function from within their message loop to ensure that accelerators in the address book dialog box work. When the dialog box is dismissed and MAPI calls the function pointed to by the lpfnDismiss member, clients should unhook the ACCELERATEABSDI function from their message loop.

lpfnDismiss
Pointer to a function based on the DISMISSMODELESS prototype or NULL. This member applies only to the modeless version of the dialog box only, as indicated by the DIALOG_SDI flag being set. MAPI calls the DISMISSMODELESS function when the user dismisses the modeless address dialog box, informing a client calling IAddrBook::Address that the dialog box is no longer active.
lpvDismissContext
Pointer to context information to be passed to the DISMISSMODELESS function pointed to by the lpfnDismiss member. This member applies only to the modeless version of the dialog box, as indicated by the DIALOG_SDI flag being set.
lpszCaption
Pointer to text to be used as the title for the common address dialog box.
lpszNewEntryTitle
Pointer to text to be used as the button label for the button that invokes either the New Entry dialog box or another dialog box.
lpszDestWellsTitle
Pointer to text to be used as a title for the recipient edit box controls that can appear in the modal version of the common address dialog box. This member is not used for modeless dialog boxes.
cDestFields
Count of recipient edit box controls in the modal version of the address dialog box, or zero if the dialog box is modeless. The address dialog box is open for browsing only when:
  • The cDestFields member is set to zero.
  • The DIALOG_BOX flag is set.
  • The ADDRESS_ONE flag is not set.

Setting cDestFields to 0XFFFFFFFF implies that MAPI should create the default number of recipient edit box controls. In this case, the lppszDestTitles and lpulDestComps members must be NULL.

nDestFieldFocus
Indicates the particular edit box control that should have the initial focus when the modal version of the dialog box appears. This value must be between 0 and the value of cDestFields minus 1.
lppszDestTitles
Pointer to an array of labels for buttons associated with each of the edit box controls that are displayed in the modal version of the address dialog box. The value of the cDestFields member indicates the number of labels included in the array. If the lppszDestTitles member is NULL, the Address method chooses default titles.
lpulDestComps
Pointer to an array of recipient type values, such as MAPI_TO, MAPI_CC, and MAPI_BCC, that is associated with each edit box control. The value of the CDestFields member indicates the number of recipient types included in the array. The values pointed to by lpulDestComps can be used to set the PR_RECIPIENT_TYPE property of each recipient. If the lpulDestComps member is NULL, the Address method chooses default recipient types.
lpContRestriction
Pointer to an SRestriction structure that limits the type of address entries that can be displayed in the dialog box.
lpHierRestriction
Pointer to an SRestriction structure that limits the address book containers that can supply address entries to be displayed in the dialog box.

Remarks

ADRPARM structures are used by clients and service providers to control the appearance and behavior of the MAPI common address dialog boxes. There are two varieties of the address dialog box: modeless and modal. Some of the members in the ADRPARM structure apply to both versions of the dialog box, but some only apply to one of the two versions. The following table relates the members of an ADRPARM structure to their use with the common address dialog boxes.

ADRPARM member | Type of dialog box
cbABContEntryID and lpABContEntryID | Modal and modeless
ulFlags | Modal and modeless
lpReserved | Modal and modeless
ulHelpContext and lpszHelpFileName | Modal and modeless
lpfnABSDI | Modeless
lpfnDismiss and lpvDismissContext | Modeless
lpszCaption | Modal and modeless
lpszNewEntryTitle | Modal
lpszDestWellsTitle, cDestFields, nDestFieldFocus, lppszDestTitles, and lpulDestComps | Modal
lpContRestriction | Modal and modeless
lpHierRestriction | Modal and modeless

The modeless dialog box is a read-only display of entries from one or more address book containers. The dialog box can display all entries from the selected containers or be limited to only those entries and containers that match criteria established by a restriction. The contents restriction pointed to by lpContRestriction can limit the types of entries displayed and the hierarchy restriction pointed to by lpHierRestriction can limit the containers providing the entries. To inform the caller when the dialog box has been dismissed, MAPI invokes a function provided by the caller that conforms to the DISMISSMODELESS prototype. Another function, one that conforms to the ACCELERATEABSDI prototype, is provided by MAPI and invoked by the caller in the Windows message loop to facilitate the working of accelerator keys. The modeless version of the MAPI address dialog box can be displayed when clients call IAddrBook::Address or when service providers call IMAPISupport::Address.

The following illustration shows the modeless address dialog box.

The modal dialog box is a read/write display of entries from one or more containers. Its contents can be affected in the same way as can the modeless version — by restrictions set in the lpContRestriction and lpHierRestriction members. In addition to the list box displaying container entries, the modal dialog box can contain between one and three edit box controls for holding entries selected by the user. Each edit control is associated with a particular recipient type — or PR_RECIPIENT_TYPE property — such as MAPI_TO. The modal address dialog box can be displayed by either of the Address methods or when clients call IAddrBook::Details and service providers call IMAPISupport::Details.

The following illustration shows the modal address dialog box.

This illustration includes two edit box controls because the cDestFields member of the ADRPARM structure controlling the display of this dialog box is set to 2. The first control has initial focus because the nDestFieldFocus member is set to 0.

The lpszNewEntryTitle member points to text for a button label that, when selected, causes an additional dialog box to be displayed. Typically, as is shown in the illustration of the modal dialog box, the button is labeled New and the dialog box that is displayed lists all of the types of addresses that can be created by any of the address book providers in the profile. Clients cause this New Entry dialog box to be displayed by calling IAddrBook::NewEntry and passing zero for the cbEidNewEntryTpl parameter and NULL for the lpEidNewEntryTpl parameter when the user selects the button. The information included in this dialog box comes from the MAPI one-off table.

The following illustration shows the appearance of the New Entry dialog box.

Every entry in this dialog box is associated with a template for entering the data required to create an address of the particular type. Most address book providers supply one template for every type of address entry they can create. When a user makes a selection from this dialog box, MAPI displays the corresponding template.

The most significant four bits of the ADRPARM structure's ulFlags member contain a version number identifying the version of the ADRPARM structure. The current version is 0 (zero) — or ADRPARM_HELP_CTX. The current implementation of MAPI will fail for any version of the structure other than zero.

Future versions of the structure may be completely different; they may or may not support the version-zero structure. The following macros are provided for extracting the version number from the ulFlags member and for combining it with the defined flags:

GET_ADRPARM_VERSION(ulFlags)

SET_ADRPARM_VERSION(ulFlags, ulVersion)

ADRPARM_HELP_CTX

See Also

Address Structures, ACCELERATEABSDI, DISMISSMODELESS, IAddrBook::Address, IMAPISupport::Address, SRestriction


CURRENCY

The CURRENCY structure contains a signed 64-bit integer representing a currency value.

Quick Info

Header file: MAPIDEFS.H

typedef struct tagCY
{
     unsigned long Lo;
     long     Hi;
} CURRENCY;

Members

Lo
Low-order 32 bits of the currency value.
Hi
High-order 32 bits of the currency value.

Remarks

The CURRENCY structure is a scaled integer representation of a decimal number with four digits to the right of the decimal point. A stored value of 327500, for example, is to be construed as representing a currency value of 32.7500.

The CURRENCY structure is used to describe a property of type PT_CURRENCY.

See Also

SPropValue


DTBLBUTTON

The DTBLBUTTON structure contains information about a button control for a dialog box built from a display table.

Quick Info

Header file: | MAPIDEFS.H
Related macro: | SizedDtblButton

typedef struct _DTBLBUTTON
{
     ULONG ulbLpszLabel;
     ULONG ulFlags;
     ULONG ulPRControl;
} DTBLBUTTON, FAR *LPDTBLBUTTON;

Members

ulbLpszLabel
Position in memory of the character string that is displayed on the button.
ulFlags
Bitmask of flags used to designate the format of the label pointed to by the ulbLpszLabel member. The following flag can be set:
MAPI_UNICODE
The label is in Unicode format. If the MAPI_UNICODE flag is not set, the label is in ANSI format.
ulPRControl
Property tag for a property of type PT_OBJECT that implements the IMAPIControl interface. When the button is clicked, MAPI calls the OpenProperty method for the display table's IMAPIProp implementation to retrieve this property.

Remarks

A DTBLBUTTON structure describes a button — a control that, when clicked, allows a user to begin an operation. Typically, clicking a button causes a modal dialog box to be displayed or a programmatic task to be invoked. Service providers can implement anything through a button control. If the button is supposed to perform a task based on the values of other controls, those controls must have set the DT_SET_IMMEDIATE flag.

The ulbLpszLabel member is the position in memory of the character string that is displayed on the button. Service providers can add an ampersand character (&) to indicate a Windows accelerator in the button label. Pressing an accelerator key has the same effect as clicking the button.

The ulPRControl member describes an object property that, when opened with the IMAPIProp::OpenProperty method, returns a pointer to a control object. Implementing a control object — an object that supports the IMAPIControl interface — is a way to extend the MAPI feature set and define the operation or task that occurs when the button is clicked. IMAPIControl supplies two methods for manipulating buttons: GetState to disable or enable buttons and Activate to handle button clicks.

For an overview of display tables, see Display Tables. For information about implementing a display table, see Implementing a Display Table.

See Also

Display Table Structures, DTCTL, PR_CONTROL_TYPE


DTBLCHECKBOX

The DTBLCHECKBOX structure contains information about a check box to be used in a dialog box built from a display table.

Quick Info

Header file: | MAPIDEFS.H
Related macro: | SizedDtblCheckBox

typedef struct _DTBLCHECKBOX
{
     ULONG ulbLpszLabel;
     ULONG ulFlags;
     ULONG ulPRPropertyName;
} DTBLCHECKBOX, FAR *LPDTBLCHECKBOX;

Members

ulbLpszLabel
Position in memory of the character string that is displayed with the check box.
ulFlags
Bitmask of flags used to designate the format of the check box label. The following flag can be set:
MAPI_UNICODE
The label is in Unicode format. If the MAPI_UNICODE flag is not set, the label is in ANSI format.
ulPRPropertyName
Property tag for a property of type PT_BOOLEAN. The value of this property is affected by the state of the check box.

Remarks

A DTBLCHECKBOX structure describes a check box — a control that reflects one of two states: enabled (a checked box) or disabled (an empty box).

The ulPRPropertyName member describes a Boolean property whose value is manipulated by changing the state of the check box. When the check box is first displayed, MAPI calls the GetProps method of the IMAPIProp implementation that is associated with the display table to retrieve a set of default properties. If one of the properties maps to the property tag in the DTBLCHECKBOX structure, the value for that property is displayed as the check box's initial value.

Check box controls can be modifiable, allowing a user to change their states. Modifiable check boxes set the DT_EDITABLE flag in the ulCtlFlags member of their DTCTL structure and in their PR_CONTROL_FLAGS property. When a check box changes its state, MAPI calls IMAPIProp::SetProps to set the property identified in the property tag member of the DTBLCHECKBOX structure to the new state.

For example, an address book provider might include a modifiable check box control in its configuration dialog box to manipulate the setting of a recipient's PR_SEND_RICH_INFO property. When the user selects the check box, MAPI sets this property to TRUE. When the check box is unselected, the property is set to FALSE.

For an overview of display tables, see Display Tables. For information about implementing a display table, see Implementing a Display Table.

See Also

Display Table Structures, DTCTL, PR_CONTROL_TYPE


DTBLCOMBOBOX

The DTBLCOMBOBOX structure describes a combo box control to be used in a dialog box built from a display table.

Quick Info

Header file: | MAPIDEFS.H
Related macro: | SizedDtblComboBox

typedef struct _DTBLCOMBOBOX
{
     ULONG ulbLpszCharsAllowed;
     ULONG ulFlags;
     ULONG ulNumCharsAllowed;
     ULONG ulPRPropertyName;
     ULONG ulPRTableName;
} DTBLCOMBOBOX, FAR *LPDTBLCOMBOBOX;

Members

ulbLpszCharsAllowed
An offset from the beginning of the DTBLCOMBOBOX structure to a character string filter that describes restrictions, if any, to the characters that can be entered into the combo box's edit control.

The filter is not interpreted as a regular expression and the same filter is applied to every character entered.The format of the filter is as follows:

*Any character is allowed (for example, "*").

[ ]Defines a set of characters (for example, "[0123456789]").

-Indicates a range of characters (for example, "[a-z]").

~Indicates that these characters are not allowed. (for example, "[~0-9]").

\Used to quote any of the above symbols (for example, "[\-\\\[\]]" means -, \, [, and ] characters are allowed).

ulFlags

Bitmask of flags used to designate the format of the character string filter. The following flag can be set:

MAPI_UNICODE
The filter is in Unicode format. If the MAPI_UNICODE flag is not set, the filter is in ANSI format.
ulNumCharsAllowed
Maximum number of characters that can be entered in the combo box's edit box.
ulPRPropertyName
Property tag for a property of type PT_TSTRING.
ulPRTableName
Property tag for a property of type PT_OBJECT on which an IMAPITable interface can be opened using an OpenProperty call. The table must have one column with a property that is the same type as the property identified by the ulPRPropName member. The rows of the table are used to populate the list box.

Remarks

A DTBLCOMBOBOX structure describes a combo box — a control that consists of a list box and a selection field. The list box presents the information from which a user can select, and the selection field displays the current selection. The selection field is an edit control that can also be used to enter text not already in the list.

The following dialog box includes an example of a combo box.

The two property tag members work together to coordinate the list box display with the edit control. When MAPI first displays the combo box, it calls the OpenProperty method of the IMAPIProp implementation that is associated with the display table to retrieve the table represented by the ulPRTableName member. This table has one column — a column that contains values for the property represented by the ulPRPropertyName member. Therefore, this column must be of the same type as the ulPRPropertyName property and both columns must be character strings.

The values for the column are displayed in the list box portion of the combo box. Therefore, PR_NULL is not a valid property tag for ulPRPropertyName. When a user either selects one of the rows or enters new data into the edit box, the ulPRPropertyName property is set to the selected or entered value.

To display an initial value for the edit control, MAPI calls IMAPIProp::GetProps to retrieve the property values for the display table. If one of the retrieved properties matches the property represented by the ulPRPropertyName member, its value becomes the initial value.

For an overview of display tables, see Display Tables. For information about implementing a display table, see Implementing a Display Table.

See Also

Display Table Structures, DTCTL, PR_CONTROL_TYPE


DTBLDDLBX

The DTBLDDLBX structure describes a drop-down list box control to be used in a dialog box built from a display table.

Quick Info

Header file: MAPIDEFS.H

typedef struct _DTBLDDLBX
{
     ULONG ulFlags;
     ULONG ulPRDisplayProperty;
     ULONG ulPRSetProperty;
     ULONG ulPRTableName;
} DTBLDDLBX, FAR *LPDTBLDDLBX;

Members

ulFlags
Reserved, must be zero.
ulPRDisplayProperty
Property tag for a property of type PT_TSTRING. This property is one of the columns in the table identified by the ulPRTableTable member. The values for this property are displayed in the list box.
ulPRSetProperty
Property tag for a property of any type. This property is one of the columns in the table identified by the ulPRTableTable member. When the user of the list box selects a property value for the ulPRDisplayProperty member from the rows of the table identified by the ulPRTableName member, the corresponding ulPRSetProperty member is set.
ulPRTableName
Property tag for a table property of type PT_OBJECT that can be opened using an OpenProperty call. The table should have two columns: ulPRDisplayProperty and ulPrSetProperty. The rows of the table should correspond to items in the list box.

Remarks

A DTBLDDLBX structure describes a drop-down list box — a list box control that is displayed as a single item until the user elects to expand it. The following illustration provides an example of a drop-down list box.

The three properties identified by the property tags work together to display the information in the list box and set a related property. The ulPRTableName member is a table object that is accessed through a call to IMAPIProp::OpenProperty. The table has two columns: one column for the property identified by the ulPRDisplayProperty member and the other for the property identified by the ulPRSetProperty member.

The ulPRDisplayProperty property drives the list box display. When a user selects one of the values from the display, MAPI calls IMAPIProp::SetProps to set the corresponding property as identified by the ulPRSetProperty member, meaning the property in the same row as the selected display property. The ulPRSetProperty member cannot be set to PR_NULL.

An initial value is displayed in the list box if MAPI has retrieved the property represented by the ulPRSetProperty member through a call to IMAPIProp::GetProps and located a row in the table with the value for the ulPRSetProperty member. The initial displayed value is the contents of the ulPRDisplayProperty column from that row that matches the property in the ulPRDisplayProperty member of the structure. The value returned by GetProps for the property identified by the ulPRDisplayProperty member becomes the initial value that is shown when the list box is first displayed.

For an overview of display tables, see Display Tables. For information about implementing a display table, see Implementing a Display Table.

See Also

Display Table Structures, DTCTL


DTBLEDIT

The DTBLEDIT structure describes an edit control to be used in a dialog box built from a display table.

Quick Info

Header file: | MAPIDEFS.H
Related macro: | SizedDtblEdit

typedef struct _DTBLEDIT
{
     ULONG ulbLpszCharsAllowed;
     ULONG ulFlags;
     ULONG ulNumCharsAllowed;
     ULONG ulPropTag;
} DTBLEDIT, FAR *LPDTBLEDIT;

Members

ulbLpszCharsAllowed
An offset from the beginning of the DTBLEDIT structure to a character string filter that describes restrictions, if any, to the characters that can be entered into the edit control.

The filter is not interpreted as a regular expression and the same filter is applied to every character entered.The format of the filter is as follows:

*Any character is allowed (for example, "*").

[ ]Defines a set of characters (for example, "[0123456789]").

-Indicates a range of characters (for example, "[a-z]").

~Indicates that these characters are not allowed (for example, "[~0-9]").

\Used to quote any of the above symbols (for example, "[\-\\\[\]]" means -, \, [, and ] characters are allowed).

ulFlags

Bitmask of flags used to designate the format of the character filter. The following flag can be set:

MAPI_UNICODE
The filter is in Unicode format. If the MAPI_UNICODE flag is not set, the filter is in ANSI format.
ulNumCharsAllowed
Maximum number of characters that the user can type into the edit box.
ulPropTag
Property tag for a property of type PT_TSTRING. The ulPropTag member identifies the string property whose data is displayed and edited in the edit control.

Remarks

A DTBLEDIT structure describes an edit control — an area on a dialog box that contains alphanumeric information. Almost all dialog boxes have at least one edit control. Edit controls can be modifiable by a user or read-only.

Edit controls can also be single line or multiline. Multiline edit controls typically have a scroll bar associated with them as shown in the following illustration.

For an overview of display tables, see Display Tables. For information about implementing a display table, see Implementing a Display Table.

See Also

Display Table Structures, DTCTL, IMAPIProp::GetProps, PR_CONTROL_TYPE


DTBLGROUPBOX

The DTBLGROUPBOX structure describes a group box control to be used in a dialog box that is built from a display table.

Quick Info

Header file: | MAPIDEFS.H
Related macro: | SizedDtblGroupBox

typedef struct _DTBLGROUPBOX
{
     ULONG ulbLpszLabel;
     ULONG ulFlags;
} DTBLGROUPBOX, FAR *LPDTBLGROUPBOX;

Members

ulbLpszLabel
Position in memory of the character string that accompanies the group box. If displayed, the label appears on the top, left-hand side of the box.
ulFlags
Bitmask of flags used to designate the format of the label pointed to by the ulbLpszLabel member. The following flag can be set:
MAPI_UNICODE
The label is in Unicode format. If the MAPI_UNICODE flag is not set, the label is in ANSI format.

Remarks

A DTBLGROUPBOX structure describes a group box — a control that is used to visually associate other controls in the dialog box. The highlighting technique involves surrounding the other controls by a box, as illustrated in the following dialog box.

For an overview of display tables, see Display Tables. For information about implementing a display table, see Implementing a Display Table.

See Also

Display Table Structures, DTCTL


DTBLLABEL

The DTBLLABEL structure describes a label to be used in a dialog box that is built from a display table.

Quick Info

Header file: | MAPIDEFS.H
Related macro | SizedDtblLabel

typedef struct _DTBLLABEL
{
     ULONG ulbLpszLabelName;
     ULONG ulFlags;
} DTBLLABEL, FAR *LPDTBLLABEL;

Members

ulbLpszLabelName
Position in memory of the character string label.
ulFlags
Bitmask of flags used to designate the format of the label pointed to by the ulbLpszLabelName member. The following flag can be set:
MAPI_UNICODE
The label is in Unicode format. If the MAPI_UNICODE flag is not set, the label is in ANSI format.

Remarks

A DTBLLABEL structure describes a label control — text that is displayed with another type of control to add meaning to that control. For example, most edit controls are placed next to labels to inform the user of the type of information to be entered. Some controls, such as group boxes and radio buttons, hold their own labels.

The label can include a Windows accelerator, identified as the character following the ampersand (&). Pressing the accelerator key puts the focus in the first nonlabel, nonbutton control following this label in the display table.

There is no support for multiline labels. Showing multiple lines requires multiple labels.

It is not possible to use a label as a read-only edit control. The distinction is that an edit control can be selected and copied while a label cannot.

For an overview of display tables, see Display Tables. For information about implementing a display table, see Implementing a Display Table.

See Also

Display Table Structures, DTCTL


DTBLLBX

The DTBLLBX structure describes a list box to be used in a dialog box that is built from a display table.

Quick Info

Header file: MAPIDEFS.H

typedef struct _DTBLLBX
{
     ULONG ulFlags;
     ULONG ulPRSetProperty;
     ULONG ulPRTableName;
} DTBLLBX, FAR *LPDTBLLBX

Members

ulFlags
Bitmask of flags used to eliminate a horizontal or vertical scroll bar from the list box. The following flags can be set:
MAPI_NO_HBAR
No horizontal scroll bar should be shown with the list box.
MAPI_NO_VBAR
No vertical scroll bar should be shown with the list box.
ulPRSetProperty
Property tag for a property of any type. This property is one of the columns in the table identified by the ulPRTableTable member.
ulPRTableName
Property tag for a table property of type PT_OBJECT that can be opened using an OpenProperty call. The number of columns that the table should have depends on whether or not the list box is a single or multiple selection list box. If the ulPRSetProperty member is set to PR_NULL, the list box allows multiple selection.

Remarks

A DTBLLBX structure describes a list box — a control that is used to show multiple items and allow a user to select one or more of the items.

The ulPRSetProperty member and ulPRTableName member work together; when one value is chosen from the table, it is written back to ulPRSetProperty when the dialog box is dismissed.

The flags value indicates whether or not a horizontal or vertical scroll bar should be displayed with the list box. The default is to have types of scroll bars appear if necessary. Service providers can set MAPI_NO_HBAR to suppress a horizontal scroll bar and MAPI_NO_VBAR to suppress a vertical scroll bar.

The two property tag members work together to display values in the list box and set corresponding properties when an item in the list box is selected. When MAPI first displays the list box, it calls the IMAPIProp implementation's OpenProperty method to retrieve the table identified in the ulPRTableName member. The number of columns in the table depends on the value of the ulPRSetProperty member. If ulPRSetProperty is set to PR_NULL, the list box is a multiple selection list box based on an object that contains recipients, such as an address book container, a recipient table for a message, or a distribution list contents table.

A table for a multiple selection list box must include the following columns:

PR_DISPLAY_NAME

PR_ENTRYID

PR_INSTANCE_KEY

PR_DISPLAY_TYPE and a maximum of five other multivalued string properties can also be displayed with the three required columns.

If the ulPRSetProperty member is not set to PR_NULL, the list box is a single selection list box. The initial value of ulPRSetProperty determines the initially selected row. When a user selects one of the rows, the ulPRSetProperty member is set to the selected value and this value is written back to the property interface implementation with a call to IMAPIProp::SetProps.

For an overview of display tables, see Display Tables. For information about implementing a display table, see Implementing a Display Table.

See Also

Display Table Structures, DTCTL


DTBLMVDDLBOX

The DTBLMVDDLBOX structure describes a drop-down list box to be used in a dialog box that is built from a display table.

Quick Info

Header file: MAPIDEFS.H

typedef struct _DTBLMVDDLBX
{
     ULONG ulFlags;
     ULONG ulMVPropTag;
} DTBLMVDDLBX, FAR * LPDTBLMVDDLBX;

Members

ulFlags
Reserved; must be zero.
ulMVPropTag
Property tag for a multivalued property of type PT_MV_TSTRING. The different values of this property are displayed as distinct entries in the drop-down list box.

Remarks

A DTBLMVDDLBOX structure describes a multivalued drop-down list box — a read-only list of items. With a multivalued drop-down list box, values are displayed when a user clicks on a scroll bar.

The data that is displayed comes from the property identified in the ulMVPropTag member. There is no need to read from the property interface that is associated with the display table. Also, because users are not allowed to make selections from these types of list boxes, data is not written to the property interface.

Only multivalued string properties are supported for the multivalued drop-down list box; other multivalued property types are not supported.

For an overview of display tables, see Display Tables. For information about implementing a display table, see Implementing a Display Table.

See Also

Display Table Structures, DTCTL


DTBLMVLISTBOX

The DTBLMVLISTBOX structure describes a multivalued list box to be displayed in a dialog box that is built from a display table.

Quick Info

Header file: MAPIDEFS.H

typedef struct _DTBLMVLISTBOX
{
     ULONG ulFlags;
     ULONG ulMVPropTag;
} DTBLMVLISTBOX, FAR * LPDTBLMVLISTBOX;

Members

ulFlags
Reserved; must be zero.
ulMVPropTag
Property tag for a multivalued property of type PT_MV_TSTRING.

Remarks

A DTBLMVLISTBOX structure describes a standard multivalued list box — a read-only list of items. With a standard multivalued list box, the values are displayed immediately.

The data that is displayed comes from the property identified in the ulMVPropTag member. There is no need to read from the property interface that is associated with the display table. Also, because users are not allowed to make selections from these types of list boxes, data is not written to the property interface.

Only multivalued string properties are supported for the multivalued list box; other multivalued property types are not supported.

For an overview of display tables, see Display Tables. For information about implementing a display table, see Implementing a Display Table.

See Also

Display Table Structures, DTCTL


DTBLPAGE

The DTBLPAGE structure describes a tabbed page to be used in a dialog box that is built from a display table.

Quick Info

Header file: | MAPIDEFS.H
Related macro: | SizedDtblPage

typedef struct _DTBLPAGE
{
     ULONG ulbLpszLabel;
     ULONG ulFlags;
     ULONG ulbLpszComponent;
     ULONG ulContext;
} DTBLPAGE, FAR *LPDTBLPAGE;

Members

ulbLpszLabel
Position in memory of the character string label for the page tab.
ulFlags
Bitmask of flags used to designate the format of the label pointed to by the ulbLpszLabelName member. The following flag can be set:
MAPI_UNICODE
The label is in Unicode format. If the MAPI_UNICODE flag is not set, the label is in ANSI format.
ulbLpszComponent
Position in memory of a character string identifying the [Help File Mappings] section in the MAPISVC.INF configuration file or 0. The file name appearing in the MAPISVC.INF section can be used by a user to access extended Help for the tabbed page by clicking the Help button on the dialog box. For more information about the entries in MAPISVC.INF, see File Format of MAPISVC.INF.
ulContext
A unique identifier for the tabbed page within the string defined by the ulbLpszComponent member. The ulbLpszComponent member and the ulContext member must both be nonzero in order for the Help button to work. If this identifier is zero and the component string is NULL, there is no Help associated with the page.

Remarks

A DTBLPAGE structure describes a tabbed page — a control that is used to separate several related dialog boxes. Typically, these dialog boxes are property sheets for showing configuration, message, or recipient options. By clicking the tab, the user can switch from one sheet to another.

The following dialog box includes four tabbed page controls: one control for each type of property relating to a particular address type.

The component string and context identifier provide information about whether or not extended Help is available for the tabbed page and if it is available, how to access it. The component string maps to the Help file; the context identifier maps to the initial Help topic. If the context identifier is zero and the component string is NULL, extended Help is not available.

For an overview of display tables, see Display Tables. For information about implementing a display table, see Implementing a Display Table.

See Also

Display Table Structures, DTCTL


DTBLRADIOBUTTON

The DTBLRADIOBUTTON structure describes one radio button that will be part of a radio button group to be used in a dialog box that is built from a display table.

Quick Info

Header file: MAPIDEFS.H

typedef struct _DTBLRADIOBUTTON
{
     ULONG ulbLpszLabel;
     ULONG ulFlags;
     ULONG ulcButtons;
     ULONG ulPropTag;
     long lReturnValue;
} DTBLRADIOBUTTON, FAR *LPDTBLRADIOBUTTON;

Members

ulbLpszLabel
Position in memory of the character string label for the radio button.
ulFlags
Bitmask of flags used to designate the format of the label pointed to by the ulbLpszLabel member. The following flag can be set:
MAPI_UNICODE
The label is in Unicode format. If the MAPI_UNICODE flag is not set, the label is in ANSI format.
ulcButtons
Count of buttons in the radio button group. The DTBLRADIOBUTTON structures for the other buttons in the group must be contained in successive rows of the display table. Each of these rows should contain the same value for the ulcButtons member.
ulPropTag
Property tag for a property of type PT_LONG. The initial selection within the radio button group is based on the initial value of this property. Each button in the group must have ulPropTag set to the same property.
lReturnValue
Unique number that identifies the selected button.

Remarks

A DTBLRADIOBUTTON structure describes a radio button — a button control that is associated with a group of buttons. Only one button in the group can be checked; setting one button causes the other buttons in the group to be unset. The following dialog box includes an example of a group of three radio button controls.

The button count is the number of radio buttons in the group. The structures for the other radio buttons in the group must be in subsequent rows in the display table. Each of these structures should have the same value for its button count.

For an overview of display tables, see Display Tables. For information about implementing a display table, see Implementing a Display Table.

See Also

Display Table Structures, BuildDisplayTable, DTCTL, SizedDtblButton


DTCTL

The DTCTL structure describes a control to be used in a dialog box built from a display table.

Quick Info

Header file: MAPIUTIL.H

typedef struct
{
     ULONG      ulCtlType;
     ULONG      ulCtlFlags;
     LPBYTE     lpbNotif;
     ULONG      cbNotif;
     LPTSTR     lpszFilter;
     ULONG      ulItemID;
     union
     {
          LPVOID               lpv;
          LPDTBLLABEL          lplabel;
          LPDTBLEDIT           lpedit;
          LPDTBLLBX            lplbx;
          LPDTBLCOMBOBOX       lpcombobox;
          LPDTBLDDLBX          lpddlbx;
          LPDTBLCHECKBOX       lpcheckbox;
          LPDTBLGROUPBOX       lpgroupbox;
          LPDTBLBUTTON         lpbutton;
          LPDTBLRADIOBUTTON    lpradiobutton;
          LPDTBLMVLISTBOX      lpmvlbx;
          LPDTBLMVDDLBX        lpmvddlbx;
          LPDTBLPAGE           lppage;
     } ctl;
} DTCTL, FAR *LPDTCTL;

Members

ulCtlType
Type of control that is included in the ctl member and corresponds to the control's PR_CONTROL_TYPE property. Possible values are:
DTCT_LABEL
Label control.
DTCT_EDIT
Edit control.
DTCT_LBX
List box control.
DTCT_COMBOBOX
Combo box control.
DTCT_DDLBX
Drop-down list box control.
DTCT_CHECKBOX
Check box control.
DTCT_GROUPBOX
Group box control.
DTCT_BUTTON
Button control.
DTCT_PAGE
Tabbed page control.
DTCT_RADIOBUTTON
Radio button control.
DTCT_MVLISTBOX
Multivalued list box control.
DTCT_MVDDLBX
Multivalued drop-down list box control.
ulCtlFlags
Bitmask of flags that describes the control's features and corresponds to the control's PR_CONTROL_FLAGS property. These flags can be set for check boxes, combo boxes, list boxes, and edit controls only. Possible values are:
DT_ACCEPT_DBCS
Either the ANSI or DBCS format is accepted. This flag is valid for edit controls only.
DT_EDITABLE
A user can edit the text in the control.
DT_MULTILINE
The control can contain multiple text lines. This flag is valid for edit controls only.
DT_PASSWORD_EDIT
The control contains a password; therefore, the contents of the control should not be displayed to the user. This flag is valid for edit controls only.
DT_REQUIRED
The dialog box control is required. This flag is valid only for edit and combo box controls.
DT_SET_IMMEDIATE
Enables immediate output of a value upon a change in the control, allowing a dependency relationship to be established between two controls.
lpbNotif
Pointer to a structure made up of a globally unique identifier, or GUID structure, to represent the service provider and an identifier for the control. The lpbNotif and cbNotif members correspond to the control's PR_CONTROL_ID property and are used to notify the user interface when the control needs updating.
cbNotif
Count of bytes in the structure pointed to by the lpbNotif member.
lpszFilter
Pointer to a character string that describes which characters can be entered into an edit or combo box control. For other types of controls, the lpszFilter member can be NULL. For edit and combo box controls, it should be a regular expression that applies to a single character at a time. The same filter is applied to all characters in the control.

The format of the filter string is as follows:

*Any character is allowed (for example, "*").

[ ]Defines a set of characters (for example, "[0123456789]").

-Indicates a range of characters (for example, "[a-z]").

~Indicates that these characters are not allowed (for example, "[~0-9]").

\Used to quote any of the above symbols (for example, "[\-\\\[\]]" means -, \, [, and ] characters are allowed).

ulItemID
Value that identifies the control in the dialog box resource. For tabbed pages — controls of type DTCT_PAGE — the ulItemID member is optionally used to load the component name for the page from a string resource. Position and label information are read from the dialog box resource.
ctl
A structure that holds the data for the control and corresponds to the control's PR_CONTROL_STRUCTURE property. Each type of control has a different structure.

Remarks

The DTCTL structure describes one control of any type. Most of its members are used to set properties on the control.

The ctl member is a union of structures that relate to a particular type of control. If the DTCTL structure is describing an edit control, for example, the ctl member will point to an DTBLEDIT structure. This structure corresponds to the control's PR_CONTROL_STRUCTURE property. The union has as its first member a variable of type LPVOID to permit compile time initialization of the DTCTL structure.

Although the BuildDisplayTable function uses the DTCTL structure for building the display table from control resources, the DTCTL structure never appears in the display table itself. This structure simply supplies information to BuildDisplayTable.

In the ulCtlFlags member, four flags — DT_ACCEPT_DBCS, DT_EDITABLE, DT_MULTILINE_and DT_PASSWORD_EDIT — affect edit controls only. Two others — DT_REQUIRED and DT_SET_IMMEDIATE — affect any editable control.

The controls available for a dialog box are label, edit box, ink-aware edit box, list box, drop-down list box, combo box, check box, group box, button, radio button, and tabbed page.

For an overview of display tables, see Display Tables. For information about implementing a display table, see Implementing a Display Table.

See Also

Display Table Structures, BuildDisplayTable, DTBLBUTTON, DTBLCHECKBOX, DTBLCOMBOBOX, DTBLDDLBX, DTBLEDIT, DTBLGROUPBOX, DTBLLABEL, DTBLLBX, DTBLMVDDLBOX, DTBLMVLISTBOX, DTBLPAGE, DTBLRADIOBUTTON


DTPAGE

The DTPAGE structure describes the dialog box that is built from a display table by the BuildDisplayTable function.

Quick Info

Header file: MAPIUTIL.H

typedef struct DTPAGE
{
     ULONG        cctl;
     LPTSTR       lpszResourceName;
     union
     {
          LPTSTR              lpszComponent;
          ULONG               ulItemID;
      }
     LPDTCTL      lpctl;
}    DTPAGE, FAR *LPDTPAGE;

Members

cctl
Count of controls pointed to by the lpctl member.
lpszResourceName
Pointer to the name or integer identifier for the dialog box resource.
lpszComponent

Pointer to the string that appears in the [Help File Mappings] section in MAPISVC.INF. Because lpszComponent is in a union with the ulItemID member, only one of these members has valid data.

ulItemID

Integer resource identifier with a value less than or equal to 65535 from which the Help file name can be read. Because ulItemID is in a union with the lpszComponent member, only one of these members has valid data.

lpctl
Pointer to an array of DTCTL structures, one for each control on the page.

Remarks

To identify the Help file for the tabbed page, set either the lpszComponent member to a hard-coded string or the ulItemID member to an integer resource identifier.

Each entry in the [Help File Mappings] section in MAPISVC.INF consists of a component string, no longer than 30 characters, on the left side and a Help file path on the right. Both ulItemID and lpszResourceName are found in the hInstance parameter of BuildDisplayTable. For more information, see MAPISVC.INF [Help File Mappings] Section.

Although BuildDisplayTable uses this structure to build the display table from control resources, the DTPAGE structure never appears in the display table itself.

For an overview of display tables, see Display Tables. For information about implementing a display table, see Implementing a Display Table.

See Also

Display Table Structures, BuildDisplayTable, DTBLPAGE, DTCTL


ENTRYID

The ENTRYID structure contains an entry identifier for a MAPI object.

Quick Info

Header file: | MAPIDEFS.H
Related macros: | CbNewENTRYID SizedENTRYID

typedef struct
{
     BYTE        abFlags[4];
     BYTE        ab[MAPI_DIM];
} ENTRYID, FAR *LPENTRYID;

Members

abFlags
Bitmask of flags that provide information describing the object. Only the first byte of the flags, abFlags[0], may be set by the provider; the other three are reserved. These flags must not be set for permanent entry identifiers; they are only set for short-term entry identifiers. To clients, this structure is read-only.

The following flags can be set in abFlags[0]:

MAPI_NOTRECIP
The entry identifier cannot be used as a recipient on a message.
MAPI_NOTRESERVED
Other users cannot access the entry identifier.
MAPI_NOW
The entry identifier cannot be used at other times.
MAPI_SHORTTERM
The entry identifier is short-term. All other values in this byte must be set unless other uses of the entry identifier are allowed.
MAPI_THISSESSION
The entry identifier cannot be used on other sessions.
ab
Indicates an array of binary data used by service providers. The client application cannot use this array.

Remarks

The ENTRYID structure is used by message store and address book providers to construct unique identifiers for their objects. Entry identifiers are used to identify the following types of objects:

Message stores

Folders

Messages

Address book containers

Distribution lists

Messaging users

Status objects

Profile sections

Each provider uses a format for the ENTRYID structure that makes sense for that provider.

Entry identifiers cannot be compared directly because one object can be represented by two different binary values. To determine if two entry identifiers represent the same object, call the IMAPISession::CompareEntryIDs method.

When a client calls an object's IMAPIProp::GetProps method to retrieve its entry identifier, the object returns the most permanent form of the entry identifier. A client can verify that an entry identifier is long-term by checking that none of the flags are set in the first byte of the abFlags member.

When a client accesses an entry identifier through a column in a table, most likely this entry identifier is short-term rather than long-term. Short-term entry identifiers can be used to open their corresponding objects only in the current MAPI session. A client can verify that an entry identifier is short-term by checking that all of the flags are set in the first byte of the abFlags member.

Some entry identifiers are short-term, but have long-term use. Such an entry identifier will have one or more of the appropriate flags set in the first byte of its abFlags member.

An ENTRYID structure is similar to a FLATENTRY structure. However, there are some differences:

  • An ENTRYID structure does not store the size of the entry identifier; a FLATENTRY structure does.
  • An ENTRYID structure stores the flag data and the rest of the entry identifier separately; a FLATENTRY structure stores the flag data with the rest of the entry identifier.
  • An ENTRYID structure is passed as a parameter to the methods of the IMAPIProp interface and to the following OpenEntry methods:

    IABLogon::OpenEntry

    IAddrBook::OpenEntry

    IMAPIContainer::OpenEntry

    IMAPISession::OpenEntry

    IMAPISupport::OpenEntry

    IMsgStore::OpenEntry

    IMSLogon::OpenEntry

  • An ENTRYID structure is used to store an entry identifier on disk. A FLATENTRY structure is used to store an entry identifier in a file or pass it in a stream of bytes.

Clients should always pass in naturally aligned entry identifiers. Although providers should handle arbitrarily aligned entry identifiers, clients should not expect this behavior. Failure to pass a suitable aligned entry identifier to a method can result in an alignment fault on RISC processors.

The natural alignment factor, typically 8 bytes, is the largest data type supported by the CPU, and usually the same alignment factor used by the system memory allocator. A naturally aligned memory address allows the CPU to access any data type it supports at that address without generating an alignment fault. For RISC CPUs, a data type of size N bytes must usually be aligned on an even multiple of N bytes, with the address being an even multiple of N.

For more information, see Entry Identifiers.

See Also

ID Structures, IMAPISupport::CompareEntryIDs, PR_RECORD_KEY


ENTRYLIST

The ENTRYLIST structure is an array of entry identifiers representing MAPI objects.

Quick Info

Header file: MAPIDEFS.H

typedef SBinaryArray ENTRYLIST, FAR *LPENTRYLIST;

See Also

ID Structures, ENTRYID, SBinaryArray


ERROR_NOTIFICATION

The ERROR_NOTIFICATION structure describes information relating to a critical error, causing an error notification to be generated.

Quick Info

Header file: MAPIDEFS.H

typedef struct _ERROR_NOTIFICATION
{
     ULONG         cbEntryID;
     LPENTRYID     lpEntryID;
     SCODE         scode;
     ULONG         ulFlags;
     LPMAPIERROR   lpMAPIError;
} ERROR_NOTIFICATION;

Members

cbEntryID
Count of bytes in the entry identifier pointed to by lpEntryID.
lpEntryID
Pointer to the entry identifier of the object causing the error.
scode
Error value for the critical error.
ulFlags
Bitmask of flags used to designate the format of the text pointed to by the lpszError member in the structure pointed to by lpMAPIError. The following flag can be set:
MAPI_UNICODE
The passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lpMAPIError
Pointer to a MAPIERROR structure describing the error.

Remarks

The ERROR_NOTIFICATION structure is one of the members of the union of structures included in the info member of the NOTIFICATION structure. When the info member of a NOTIFICATION structure contains an ERROR_NOTIFICATION structure, the ulEventType member of the NOTIFICATION structure is set to fnevCriticalError.

The value of the cbEntryID member and the lpEntryID member can be NULL.

For more information about notification, see the topics described in the following table.

Topic | Description
Event Notification in MAPI | General overview of notification and notification events.
Handling Notifications | Discussion of how clients should handle notifications.
Supporting Event Notification | Discussion of how service providers can use the IMAPISupport method to generate notifications.

See Also

Notification Structures, NOTIFICATION


EXTENDED_NOTIFICATION

The EXTENDED_NOTIFICATION structure describes information relating to an event that is service provider-specific.

Quick Info

Header file: MAPIDEFS.H

typedef struct _EXTENDED_NOTIFICATION
{
     ULONG    ulEvent;
     ULONG    cb;
     LPBYTE   pbEventParameters;
} EXTENDED_NOTIFICATION;

Members

ulEvent
Extended event code that is defined by the provider.
cb
Count of bytes in the event-specific parameters pointed to by pbEventParameters.
pbEventParameters
Pointer to event-specific parameters. What type of parameters are used depends on the value of the ulEvent member; these parameters are documented by the provider that issued the event.

Remarks

The EXTENDED_NOTIFICATION structure is one of the members of the union of structures included in the info member of the NOTIFICATION structure. When the info member of a NOTIFICATION structure contains an EXTENDED_NOTIFICATION structure, the ulEventType member of the NOTIFICATION structure is set to fnevExtended.

The extended event is defined by a service provider to represent a type of change that cannot be covered by any of the other predefined events. Only clients that know before they register that a service provider supports an extended event can register for that event. It is not possible for clients to determine without advanced knowledge if a service provider supports an extended event and, if it does, how to handle such an event when it is received.

An extended notification is sent by the session when a client logs off. Register for this notification by calling IMAPISession::Advise with the lpEntryID parameter set to NULL and the cbEntryID parameter set to zero.

For more information about notification, see the topics described in the following table.

Topic | Description
Event Notification in MAPI | General overview of notification and notification events.
Handling Notifications | Discussion of how clients should handle notifications.
Supporting Event Notification | Discussion of how service providers can use the IMAPISupport method to generate notifications.

See Also

Notification Structures, NOTIFICATION


FILETIME

The FILETIME structure holds an unsigned 64-bit date and time value for a file. This value represents the number of 100-nanosecond units since the beginning of January 1, 1601.

Quick Info

Header file: MAPIDEFS.H

typedef struct _FILETIME
{
     DWORD dwLowDateTime;
     DWORD dwHighDateTime;
} FILETIME, FAR *LPFILETIME;

Members

dwLowDateTime
Low-order 32 bits of the file time value.
dwHighDateTime
High-order 32 bits of the file time value.

Remarks

A property of type PT_SYSTIME has a FILETIME structure for its value. Such a property has a FILETIME data type for the Value member in its definition in an SPropValue structure.

The definition of the FILETIME structure is in the Win32 Programmer's Reference and in the MAPI header file MAPIDEFS.H. MAPI defines the structure conditionally to ensure that it is defined when the Win32 definition is unavailable.


FLAGLIST

The FLAGLIST structure contains a list of flags used to indicate the status of address entries during the name resolution process.

Quick Info

Header file: MAPIDEFS.H

typedef struct
{
     ULONG cFlags;
     ULONG ulFlags[MAPI_DIM];
} FlagList, FAR * LPFlagList;

Members

cFlags
Count of MAPI-defined flags in the list.
ulFlags
An array of flags that provides the status of the name resolution operation for a recipient. The following flags can be set:
MAPI_AMBIGUOUS
The recipient has been resolved, but not to a unique entry identifier. Other address book containers should not try to resolve this recipient.
MAPI_RESOLVED
The recipient has been resolved to a unique entry identifier. Other address book containers should not try to resolve this recipient.
MAPI_UNRESOLVED
The entry has not been resolved. Other address book containers should try to resolve this recipient.

Remarks

The FLAGLIST structure is used as a parameter to IABContainer::ResolveNames. Each of the recipients to be resolved is included in an ADRLIST structure. As the address book container attempts to resolve each recipient, it sets the appropriate flag in the corresponding entry in the FLAGLIST structure. All of the entries in the FLAGLIST structure are in the same order as the entries in the ADRLIST structure, making it easy to associate a flag setting with a recipient.

See Also

IABContainer::ResolveNames


FLATENTRY

The FLATENTRY structure is an ENTRYID structure plus a byte count that specifies the size of the ENTRYID structure.

Quick Info

Header file: | MAPIDEFS.H
Related macros: | cbFLATENTRY CbNewFLATENTRY

typedef struct
{
     ULONG  cb;
     BYTE   abEntry[MAPI_DIM];
} FLATENTRY, FAR *LPFLATENTRY;

Members

cb
Count of bytes in the abEntry member.
abEntry
The complete entry identifier, including the array of flags and binary data.

Remarks

A FLATENTRY structure is similar to an ENTRYID structure. However, there are some differences:

  • A FLATENTRY structure stores the size of the entry identifier; ENTRYID does not.
  • A FLATENTRY structure stores the flag data together with the rest of the entry identifier; ENTRYID stores them separately.
  • A FLATENTRY structure is used to store an entry identifier in a file or pass it in a stream of bytes whereas an ENTRYID structure is used by the IMAPIProp interface methods and by the following OpenEntry methods:

    IABLogon::OpenEntry

    IAddrBook::OpenEntry

    IMAPIContainer::OpenEntry

    IMAPISession::OpenEntry

    IMAPISupport::OpenEntry

    IMsgStore::OpenEntry

    IMSLogon::OpenEntry

  • A FLATENTRY structure is used to store an entry identifier in a file or pass it in a stream of bytes. An ENTRYID structure is used to store an entry identifier on disk.

See Also

ID Structures, ENTRYID


FLATENTRYLIST

The FLATENTRYLIST structure contains an array of FLATENTRY structures.

Quick Info

Header file: | MAPIDEFS.H
Related macros: | CbFLATENTRYLIST CbNewFLATENTRYLIST

typedef struct
{
     ULONG     cEntries;
     ULONG     cbEntries;
     BYTE      abEntries[MAPI_DIM];
} FLATENTRYLIST, FAR *LPFLATENTRYLIST;

Members

cEntries
Count of FLATENTRY structures in the array described by the abEntries member.
cbEntries
Count of bytes in the array described by abEntries.
abEntries
Byte array containing one or more FLATENTRY structures, arranged end to end.

Remarks

In the abEntries array, each FLATENTRY structure is aligned on a naturally aligned boundary. Extra bytes are included as padding to ensure natural alignment between any two FLATENTRY structures. The first FLATENTRY structure in the array is always aligned correctly because the offset of the abEntries member is 8. To compute the offset of the next structure, use the size of the first entry rounded up to the next multiple of 4. Use the CbFLATENTRY macro to compute the size of a FLATENTRY structure.

For example, the second FLATENTRY structure starts at an offset made up of the offset of the first entry plus the length of the first entry rounded to the next four bytes. The length of the first entry is the length of its cb member plus the length of its abEntry member.

The following code sample indicates how to compute offsets in a FLATENTRYLIST structure. Assume that lpFlatEntry is a pointer to the first structure in the list.

(offsetof(lpFlatEntry->ab)         // for example, 4
    + lpFlatEntry->cb              // size of lpFlatEntry->ab
    + 4) & ~3                      // round to next 4 byte boundary

See Also

ID Structures, FLATENTRY, PR_REPLY_RECIPIENT_ENTRIES


FLATMTSIDLIST

The FLATMTSIDLIST structure contains an array of MTSID structures, each of which contains an X.400 message transport system (MTS) entry identifier.

Quick Info

Header file: | MAPIDEFS.H
Related macros: | CbFLATMTSIDLIST CbNewFLATMTSIDLIST

typedef struct
{
     ULONG     cMTSIDs;
     ULONG     cbMTSIDs;
     BYTE      abMTSIDs[MAPI_DIM];
} FLATMTSIDLIST, FAR *LPFLATMTSIDLIST;

Members

cMTSIDs
Count of MTSID structures in the array described by the abMTSIDs member.
cbMTSIDs
Count of bytes in the array described by abMTSIDs.
abMTSIDs
Byte array containing one or more MTSID structures.

Remarks

The FLATMTSIDLIST structure's use in X.400 messaging corresponds to the FLATENTRYLIST structure's use in MAPI messaging. MAPI uses FLATMTSIDLIST structures to maintain X.400 properties during message handling. Service providers use FLATMTSIDLIST structures when handling inbound and outbound X.400 messages.

In the abMTSIDs array, each MTSID structure is aligned on a naturally aligned boundary. Extra bytes are included as padding to ensure natural alignment between any two MTSID structures. The first MTSID structure in the array is always aligned correctly because the offset of the abMTSIDs member is 8. To compute the offset of the next structure, use the size of the first entry rounded up to the next multiple of 4. Use the CbNewMTSID macro to compute the size of an MTSID structure.

See Also

ID Structures, CbNewFLATMTSIDLIST, FLATENTRYLIST, MTSID


FORMPRINTSETUP

The FORMPRINTSETUP structure describes the print setup information for the form object.

Quick Info

Header file: MAPIFORM.H

typedef struct
{
    ULONG        ulFlags;
    HDEVMODE     hDevMode;
    HDEVNAMES    hDevNames;
    ULONG        ulFirstPageNumber;
    ULONG        ulFPrintAttachments;
} FORMPRINTSETUP, FAR * LPFORMPRINTSETUP;

Members

ulFlags
Bitmask of flags that controls the type of the strings. The following flag can be used:
MAPI_UNICODE
The strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
hDevmode
Handle to the mode of the printer.
hDevnames
Handle to the path of the printer.
ulFirstPageNumber
Page number of the first page to be printed.
ulFPrintAttachments
Flag that indicates whether there are attachments to be printed. If there are attachments to print, the ulFPrintAttachments member is set to 1. If there are no attachments to print, it is set to 0.

Remarks

The FORMPRINTSETUP structure is used to describe the print setup information for a form object. Implementations of IMAPIViewContext::GetPrintSetup fill in the FORMPRINTSETUP structure and return it in the contents of the lppFormPrintSetup output parameter of GetPrintSetup.

If the MAPI_UNICODE flag is passed in the ulFlags parameter of GetPrintSetup, the strings referenced by the hDevmode and hDevnames members should be in Unicode format. Otherwise, the strings should be in ANSI format.

Form viewers implementing IMAPIViewContext must allocate the FORMPRINTSETUP structure using the MAPI allocator function MAPIAllocateBuffer, but allocate the individual members, hDevMode and hDevNames, with the Windows function GlobalAlloc. The release of memory is handled similarly. The hDevMode and hDevNames members must be freed using the Windows function GlobalFree while the FORMPRINTSETUP structure must be freed with the MAPIFreeBuffer function.

See Also

Form Structures, IMAPIViewContext::GetPrintSetup, MAPIFreeBuffer


GUID

The GUID structure describes a globally unique identifier.

Quick Info

Header file: MAPIGUID.H

typedef struct _GUID
{
    unsigned long        Data1;
    unsigned short       Data2;
    unsigned short       Data3;
    unsigned char        Data4[8];
} GUID;

Members

Data1
An unsigned long integer data value.
Data2
An unsigned short integer data value.
Data3
An unsigned short integer data value.
Data4
An array of unsigned characters.

Remarks

GUID structures are used in MAPI as follows:

  • In the MAPIUID structures that uniquely identify service providers.
  • For interface identifiers.
  • In the property set names of named properties.

Message store and address book providers call the Microsoft utility UUIDGEN.EXE to generate a GUID structure to use in their MAPIUID structure. By passing the resulting MAPIUID to IMAPISupport::SetProviderUID, these service providers inform MAPI of their unique identifier.

Also, they are used in the implementation of Microsoft Remote Procedure Call (RPC) and the Object Description Language (ODL). For more information about these uses, see the Microsoft RPC Programmer's Guide and Reference, OLE Programmer's Reference, and Inside OLE, Second Edition.

The GUID structure is defined in the Win32 Programmer's Reference. Specific values for GUID structures that are used within MAPI are defined in the MAPI header file MAPIGUID.H.

See Also

ID Structures, MAPIUID


IID

The IID structure is a GUID structure used to describe an identifier for a MAPI interface.

Remarks

An IID structure is used to uniquely identify a MAPI interface and to associate a particular interface with an object. For example, when a client calls IMAPISession::OpenEntry to open a folder, the client sets the lpInterface parameter to point to an IID representing the IMAPIFolder interface. MAPI defines the IMAPIFolder IID to be IID_IMAPIFolder. IID structures are also used to uniquely identify OLE interfaces.

All of the specific IID structures for the MAPI interfaces are defined in the MAPIGUID.H header file.

See Also

ID Structures


MAPIERROR

The MAPIERROR structure provides detailed information about an error, typically generated by the operating system, MAPI, or a service provider.

Quick Info

Header file: MAPIDEFS.H

typedef struct _MAPIERROR
{
     ULONG      ulVersion;
     LPTSTR     lpszError;
     LPTSTR     lpszComponent;
     ULONG      ulLowLevelError;
     ULONG      ulContext;

} MAPIERROR, FAR * LPMAPIERROR;

Members

ulVersion
Version number of the structure. The ulVersion member is used for future expansion and should be set to MAPI_ERROR_VERSION, which is currently defined as zero.
lpszError
Pointer to a string describing the error. This string will be in Unicode format if the ulFlags parameter to the method in which this structure is used is set to MAPI_UNICODE.
lpszComponent
Pointer to a string describing the component that generated the error. This string will be in Unicode format if the ulFlags parameter to the method in which this structure is used is set to MAPI_UNICODE.
ulLowLevelError
Low-level error value used only when the error to be returned is low-level.
ulContext
Value that represents the location within the component pointed to by the lpszComponent member that identifies where the error occurred.

Remarks

The MAPIERROR structure is used to describe error information. Clients and service providers pass a pointer to a MAPIERROR structure in the lppMAPIError parameter of the IMAPIProp::GetLastError method. GetLastError returns information about the previous error that has occurred to an object. Callers of GetLastError free the memory for the MAPIERROR structure by calling MAPIFreeBuffer.

The lpszComponent member can be used to map the component's Help file, if one exists. Service providers should limit the size of the component string to 30 characters so that it can easily be displayed in a dialog box. The ulContext member can also be used to refer to an online Help topic for common errors.

Because service providers are not required to provide detailed error information, clients should not expect any of the members of the MAPIERROR structure that are returned to contain valid data. However, at a minimum MAPI strongly recommends that providers specify information in the lpszComponent and ulContext members.

For more information about error handling in MAPI, see Error Handling.

See Also

IABLogon::GetLastError, IABProvider::Logon, IMAPIControl::GetLastError, IMAPIProp::GetLastError, IMAPISession::GetLastError, IMAPISupport::GetLastError, IMAPISupport::OpenAddressBook, IMAPISession::OpenAddressBook, IMAPITable::GetLastError, IMsgServiceAdmin::GetLastError, IMSLogon::GetLastError, IMSProvider::Logon, IProfAdmin::GetLastError, IProviderAdmin::GetLastError


MAPIINIT_0

The MAPIINIT_0 structure conveys options to the MAPIInitialize function.

Quick Info

Header file: MAPIX.H

typedef struct
{
     ULONG ulVersion;
     ULONG ulFlags;
} MAPIINIT_0, FAR *LPMAPIINIT_0;

Members

ulVersion
Integer value representing the version number of the MAPIINIT_0 structure. The ulVersion member is for future expansion and does not represent the version of the MAPI interface. Currently, ulVersion must be set to MAPI_INIT_VERSION.
ulFlags
Bitmask of flags used to control the initialization of the MAPI session. The following flags can be set:
MAPI_MULTITHREAD_NOTIFICATIONS
MAPI should generate notifications using a thread dedicated to notification handling rather than the first thread used to call MAPIInitialize.
MAPI_NT_SERVICE
The caller is running as a Windows NT service. Callers that are not running as a Windows NT service should not set this flag; callers that are running as a service must set this flag.

Remarks

Multithreaded clients running under Windows NT or Windows 95 should set the MAPI_MULTITHREADED_NOTIFICATIONS flag. If the flag is not set, notifications are generated on the thread used to make the first call to MAPIInitialize.

For more information about when to set this flag and how to implement thread safety in a client, see Threading in MAPI.

See Also

MapiInitialize


MAPINAMEID

The MAPINAMEID structure is used to describe a named property.

Quick Info

Header file: MAPIDEFS.H

typedef struct _MAPINAMEID
{
     LPGUID lpguid;
     ULONG  ulKind;
     union
     {
          LONG    lID;
          LPWSTR  lpwstrName;
     } Kind;
} MAPINAMEID, FAR *LPMAPINAMEID;

Members

lpguid
Pointer to a GUID structure defining a particular property set; this member cannot be NULL. Valid values are:
PS_PUBLIC_STRINGS
PS_MAPI
A client-defined value
ulKind
Value describing the type of value in the Kind member. Valid values are:
MNID_ID
The Kind member contains an integer value representing the property name.
MNID_STRING
The Kind member contains a Unicode character string representing the property name.
Kind
Union describing the name of the named property. The name can either be an integer value, stored in lID, or a Unicode character string, stored in lpwstrName.

Remarks

The MAPINAMEID structure is used to describe named properties — properties that have identifiers over 0x8000. A property set is an integral part of a named property. For example PS_PUBLIC_STRINGS or PS_ROUTING_ADDRTYPE are property sets defined by MAPI.

Named properties enable clients to define custom properties in a larger name space than is available in the MAPI-defined property identifier range. Property names cannot be used to obtain property values directly; they must first be mapped to property identifiers through the IMAPIProp::GetIDsFromNames method. For particular objects such as messages, MAPI reserves a range of property identifiers for custom properties. Therefore, for these objects, clients need not use named properties and can save the associated overhead.

For more information about named properties, see Named Properties.

See Also

ID Structures, GUID, IMAPIProp::GetIDsFromNames


MAPIUID

The MAPIUID structure is a byte-order independent version of a GUID structure and is used to uniquely identify a service provider.

Quick Info

Header file: | MAPIDEFS.H
Related macro: | IsEqualMAPIUID

typedef struct _MAPIUID
{
     BYTE ab[16];
} MAPIUID, FAR *LPMAPIUID;

Members

ab
An array containing a 16-byte identifier.

Remarks

A MAPIUID structure — MAPI unique identifier — is a GUID structure put into Intel® processor byte order. That is, MAPIUID and GUID structures have the same byte order when used on an Intel-processor computer. However, on a computer that uses a different byte order — for example, a Motorola®-processor computer — the MAPIUID has the same byte order as on the Intel machine and the GUID uses the byte order specific to the Motorola-processor computer.

MAPI creates MAPIUID structures in a way that makes it extremely rare for two different items to have the same identifier. MAPIUID structures can be stored as binary properties or as files, without regard to the byte ordering of the computer storing or accessing the information.

MAPIUID structures are used:

  • To identify a profile section.
  • In the entry identifiers of message store and address book objects to identify the responsible service provider.
  • In the PR_SEARCH_KEY property of messages.

To generate a MAPIUID identifier for a profile section or an entry identifier, service providers call the Microsoft utility UUIDGEN.EXE. To generate a MAPIUID identifier for a search key, service providers call IMAPISupport::NewUID.

When a client transmits a message across a network, it should use a protocol or transmission format that does not change the byte order of MAPIUID data.

For more information about how MAPIUID structures are used, see the following topics:

Registering Service Provider Unique Identifiers

Registering a Preprocessor

Setting Transport Order

See Also

ID Structures, GUID, IMAPISession::OpenProfileSection, IMAPISupport::NewUID


MTSID

The MTSID structure contains an X.400 message transport system (MTS) entry identifier.

Quick Info

Header file: | MAPIDEFS.H
Related macros: | CbMTSID CbNewMTSID

typedef struct
{
     ULONG         cb;
     BYTE          ab[MAPI_DIM];
} MTSID, FAR *LPMTSID;

Members

cb
Count of bytes in the array described by the abEntry member.
abEntry
Byte array containing the MTS entry identifier data.

Remarks

The MTSID structure is used only for X.400 mappings of MAPI entry identifiers. It corresponds to the MAPI FLATENTRY structure.

An MTS identifier has the same format as a MAPI entry identifier or a binary property value. MTS identifiers can be particularly useful for canceling deferred messages.

See Also

ID Structures, FLATENTRY, FLATMTSIDLIST


NEWMAIL_NOTIFICATION

The NEWMAIL_NOTIFICATION structure describes information relating to the arrival of a new message.

Quick Info

Header file: MAPIDEFS.H

typedef struct _NEWMAIL_NOTIFICATION
{
     ULONG      cbEntryID;
     LPENTRYID  lpEntryID;
     ULONG      cbParentID;
     LPENTRYID  lpParentID;
     ULONG      ulFlags;
     LPTSTR     lpszMessageClass;
     ULONG      ulMessageFlags;
} NEWMAIL_NOTIFICATION;

Members

cbEntryID
Count of bytes in the entry identifier pointed to by the lpEntryID member.
lpEntryID
Pointer to the entry identifier of the newly arrived message.
cbParentID
Count of bytes in the entry identifier pointed to by the lpParentID member.
lpParentID
Pointer to the entry identifier of the receive folder for the newly arrived message.
ulFlags
Bitmask of flags used to describe the format of the string properties included with the message. The following flag can be set:
MAPI_UNICODE
The passed-in strings are in Unicode format. If the MAPI_UNICODE flag is not set, the strings are in ANSI format.
lpszMessageClass
Pointer to the message class of the newly arrived message.
ulMessageFlags
Bitmask of flags that describes the current state of the newly arrived message. The ulMessageFlags member is a copy of the message's PR_MESSAGE_FLAGS property.

Remarks

The NEWMAIL_NOTIFICATION structure is one of the members of the union of structures included in the info member of the NOTIFICATION structure. When the info member of a NOTIFICATION structure contains a NEWMAIL_NOTIFICATION structure, the ulEventType member of the NOTIFICATION structure is set to fnevNewMail.

MAPI uses the NEWMAIL_NOTIFICATION structure only as a member of the NOTIFICATION structure, which holds information about a notification event for the advise sink.

For more information about notification, see the topics described in the following table.

Topic | Description
Event Notification in MAPI | General overview of notification and notification events.
Handling Notifications | Discussion of how clients should handle notifications.
Supporting Event Notification | Discussion of how service providers can use the IMAPISupport method to generate notifications.

See Also

Notification Structures, NOTIFICATION, PR_MESSAGE_FLAGS


NOTIFICATION

The NOTIFICATION structure contains information about an event that has occurred and the data that has been affected by the event.

Quick Info

Header file: MAPIDEFS.H

typedef struct
{
     ULONG     ulEventType;
     union
     {
          ERROR_NOTIFICATION         err;
          NEWMAIL_NOTIFICATION       newmail;
          OBJECT_NOTIFICATION        obj;
          TABLE_NOTIFICATION         tab;
          EXTENDED_NOTIFICATION      ext;
          STATUS_OBJECT_NOTIFICATION statobj;
     } info;
} NOTIFICATION, FAR *LPNOTIFICATION;

Members

ulEventType
Type of notification event that occurred. The value of the ulEventType member corresponds to the structure that is included in the info union.

The ulEventType member can be set to one of the following values:

fnevCriticalError
A global error has occurred, such as a session shut down in progress. The info member contains an ERROR_NOTIFICATION structure.
fnevExtended
An internal event defined by a particular service provider has occurred. The info member contains an EXTENDED_NOTIFICATION structure.
fnevNewMail
A message has been delivered to the appropriate receive folder for the message class and is waiting to be processed. The info member contains an NEWMAIL_NOTIFICATION structure.
fnevObjectCopied
A MAPI object has been copied. The info member contains an OBJECT_NOTIFICATION structure.
fnevObjectCreated
A MAPI object has been created. The info member contains an OBJECT_NOTIFICATION structure.
fnevObjectDeleted
A MAPI object has been deleted. The info member contains an OBJECT_NOTIFICATION structure.
fnevObjectModified
A MAPI object has changed. The info member contains an OBJECT_NOTIFICATION structure.
fnevObjectMoved
A message store or address book object has been moved. The info member contains an OBJECT_NOTIFICATION structure.
fnevSearchComplete
A search operation has finished and the results are available. The info member contains an OBJECT_NOTIFICATION structure.
fnevTableModified
Information in a table has changed. The info member contains an TABLE_NOTIFICATION structure.
info
Union of notification structures describing the affected data for a particular type of event. The structure included in the info member depends on the value of the ulEventType member.

Remarks

One or more NOTIFICATION structures are passed as input parameters with every call to a registered advise sink's IMAPIAdviseSink::OnNotify method. The NOTIFICATION structures contain information about the particular events that have occurred and describe the affected objects.

Before clients or service providers receiving a notification can use the structure to process the event, they must check the event type as indicated in the ulEventType member. For example, the code sample below checks for the arrival of a new message and upon detecting an event of this type, prints out the message class of the message.

if (pNotif -> ulEventType == fnevNewMail)
{
     printf("%s\n", pNotif -> newmail.lpszMessageClass)
}

For more information about notification, see the topics described in the following table.

Topic | Description
Event Notification in MAPI | General overview of notification and notification events.
Handling Notifications | Discussion of how clients should handle notifications.
Supporting Event Notification | Discussion of how service providers can use the IMAPISupport method to generate notifications.

See Also

Notification Structures, ERROR_NOTIFICATION, EXTENDED_NOTIFICATION, NEWMAIL_NOTIFICATION, OBJECT_NOTIFICATION, STATUS_OBJECT_NOTIFICATION, TABLE_NOTIFICATION


NOTIFKEY

The NOTIFKEY structure uniquely identifies a connection between an advise sink, an advise source, and MAPI. The Subscribe and Notify methods of IMAPISupport use the NOTIFKEY structure to generate notifications to the appropriate advise sink about the appropriate advise source.

Quick Info

Header file: MAPISPI.H

typedef struct
{
     ULONG     cb;
     BYTE      ab[MAPI_DIM];
} NOTIFKEY, FAR *LPNOTIFKEY;

Members

cb
Count of bytes in the ab member.
ab
Array of bytes describing the notification key.

Remarks

Service providers generate notification keys when their Advise method is called and they want to call IMAPISupport::Subscribe to handle the notification registration and the subsequent sending of notifications. A notification key can be the entry identifier of the advise source or it can be any other identifying item such as a constant. For example, a message store provider might use the path of a folder as its notification key.

The notification key should work across multiple processes.

The scope requirements for a notification key are similar to those for a long-term entry identifier. However, unlike an entry identifier, a notification key must be binary-comparable. Typically, a notification key includes a GUID value defined by the service provider followed by other provider-specific information unique to the object.

For a discussion of the use of the NOTIFKEY structure to manage the connections between the advise sinks and the objects that generate the notifications, see Supporting Event Notification.

See Also

Notification Structures


OBJECT_NOTIFICATION

The OBJECT_NOTIFICATION structure contains information about an object that has undergone a change, such as being copied or modified.

Quick Info

Header file: MAPIDEFS.H

typedef struct _OBJECT_NOTIFICATION
{
     ULONG             cbEntryID;
     LPENTRYID         lpEntryID;
     ULONG             ulObjType;
     ULONG             cbParentID;
     LPENTRYID         lpParentID;
     ULONG             cbOldID;
     LPENTRYID         lpOldID;
     ULONG             cbOldParentID;
     LPENTRYID         lpOldParentID;
     LPSPropTagArray   lpPropTagArray;
} OBJECT_NOTIFICATION;

Members

cbEntryID
Count of bytes in the entry identifier pointed to by the lpEntryID member.
lpEntryID
Pointer to the entry identifier of the affected object.
ulObjType
Type of object affected. Possible types are:
MAPI_STORE
Message store.
MAPI_ADDRBOOK
Address book.
MAPI_FOLDER
Folder.
MAPI_ABCONT
Address book container.
MAPI_MESSAGE
Message.
MAPI_MAILUSER
Messaging user.
MAPI_ATTACH
Attachment.
MAPI_DISTLIST
Distribution list.
MAPI_PROFSECT
Profile section.
MAPI_STATUS
Status object.
MAPI_SESSION
Session object.
cbParentID
Count of bytes in the entry identifier pointed to by the lpParentID member.
lpParentID
Pointer to the entry identifier of the parent of the affected object.
cbOldID
Count of bytes in the entry identifier pointed to by the lpOldID member.
lpOldID
Pointer to the entry identifier of the original object. This pointer can be NULL if the event does not require an original object.
cbOldParentID
Count of bytes in the entry identifier pointed to by the lpOldParentID member.
lpOldParentID
Pointer to the entry identifier of the parent of the original object. This pointer can be NULL if the event does not require an original object.
lpPropTagArray
Pointer to an SPropTagArray structure containing the property tags identifying properties affected by the event.

Remarks

The OBJECT_NOTIFICATION structure is one of the members of the union of structures included in the info member of the NOTIFICATION structure. When the info member of a NOTIFICATION structure contains an OBJECT_NOTIFICATION structure, the ulEventType member of the NOTIFICATION structure is set to one of the following types of events:

fnevObjectCreated

fnevObjectModified

fnevObjectDeleted

fnevObjectMoved

fnevObjectCopied

fnevSearchComplete

The search complete event, represented by the fnevSearchComplete event type, indicates that the initial search of the domain for one search folder has completed.

The members that contain information about the original object, cbOldID, lpOldID, cbOldParentID, and lpOldParentID, are used only in move and copy events. These members do not apply to the other types of events.

For more information about notification, see the topics described in the following table.

Topic | Description
Event Notification in MAPI | General overview of notification and notification events.
Handling Notifications | Discussion of how clients should handle notifications.
Supporting Event Notification | Discussion of how service providers can use the IMAPISupport method to generate notifications.

See Also

Notification Structures, NOTIFICATION, SPropTagArray


OPTIONDATA

The OPTIONDATA structure describes properties supported by a transport provider.

Quick Info

Header file: MAPISPI.H

typedef struct _OPTIONDATA
{
     ULONG           ulFlags;
     LPGUID          lpRecipGUID;
     LPTSTR          lpszAdrType;
     LPTSTR          lpszDLLName;
     ULONG           ulOrdinal;
     ULONG           cbOptionsData;
     LPBYTE          lpbOptionsData;
     ULONG           cOptionsProps;
     LPSPropValue    lpOptionsProps;
} OPTIONDATA, FAR *LPOPTIONDATA;

Members

ulFlags
Flags used to specify the type of option properties. One of the following flags must be set:
MAPI_MESSAGE
The properties are message-specific options.
MAPI_RECIPIENT
The properties are recipient-specific options.
lpRecipGUID
Pointer to a GUID structure identifying the message recipient, if the ulFlags member is set to MAPI_RECIPIENT. When lpRecipGUID points to a valid GUID structure, recipient options are restricted to only those recipients that have in their entry identifiers the value of lpRecipGUID.
lpszAdrType
Pointer to an e-mail address type, if the ulFlags member is set to MAPI_RECIPIENT. When lpszAdrType points to a valid address type, recipient options are restricted to only those recipients with this address type.
lpszDLLName
Pointer to the name of the DLL to be loaded. This is the DLL containing the transport provider's option callback function — the function that is called to manage the option properties.
ulOrdinal
Specifies which ordinal MAPI uses to find the option callback function.
cbOptionsData
Count of bytes in the data pointed to by the lpbOptionsData member.
lpbOptionsData
Pointer to transport provider option data that is specific to the recipient or message and is passed to the option callback function.
cOptionsProps
Count of properties in the array pointed to by the lpOptionsProps member.
lpOptionsProps
Pointer to an array of SPropValue structures, each containing the default values for the recipient or message options.

Remarks

Option properties can apply to a recipient or to a message. They often relate to an address type or GUID supported by a transport provider. Transport providers register to support option properties when MAPI calls their IXPLogon::RegisterOptions method.

RegisterOptions writes one or two OPTIONDATA structures for each supported address type, depending on whether the provider registers for both recipient and message options, recipient options only, or message options only. If a provider is registered for both option types, RegisterOptions writes one structure containing message option properties and one structure containing recipient option properties.

Clients can retrieve the current settings for these options either interactively with a property sheet or programmatically with a property value array. To display option properties to the user, clients call IMAPISession::MessageOptions or IAddrBook::RecipOptions. To retrieve option properties without user intervention, clients call IMAPISession::QueryDefaultMessageOpt or IAddrBook::QueryDefaultRecipOpt.

When a client calls MessageOptions or RecipOptions, MAPI invokes a callback function created by the transport provider that conforms to the OPTIONCALLBACK prototype. This function typically resides in the same DLL as the transport provider and is called to retrieve an IMAPIProp implementation to use with a display table for showing the message and recipient options described in the OPTIONDATA structures.

The DLL name in the lpszDLLname member should not indicate the platform when included in an OPTIONDATA structure that is passed in the lppOptions parameter to IXPLogon::RegisterOptions.

For more information, see Implementing Message and Recipient Options with Transport Providers and Message and Recipient Options.

See Also

IXPLogon::AddressTypes, IXPLogon::RegisterOptions, SPropValue


SAndRestriction

The SAndRestriction structure describes an AND restriction, which is used to join a group of restrictions using a logical AND operation.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SAndRestriction
{
     ULONG          cRes;
     LPSRestriction lpRes;
} SAndRestriction;

Members

cRes
Count of search restrictions in the array pointed to by the lpRes member.
lpRes
Pointer to an array of SRestriction structures to be combined with a logical AND operation.

Remarks

The result of the SAndRestriction is TRUE if all of its child restrictions evaluate to TRUE, and FALSE if any child restriction evaluates to FALSE.

For a description of types of restrictions, how to build them, and sample code, see About Restrictions.

See Also

Restriction Structures, SRestriction


SAppTimeArray

The SAppTimeArray structure contains an array of time values.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SAppTimeArray
{
     ULONG      cValues;
     double     FAR *lpat;
} SAppTimeArray;

Members

cValues
Count of values in the array pointed to by the lpat member.
lpat
Pointer to an array of application time values.

Remarks

The SAppTimeArray structure is used to define properties of type PT_MV_APPTIME. For more information about PT_MV_APPTIME, see List of Property Types.


SBinary

The SBinary structure describes a property of type PT_BINARY.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SBinary
{
     ULONG      cb;
     LPBYTE     lpb;
} SBinary, FAR *LPSBinary;

Members

cb
Count of bytes in the lpb member.
lpb
Pointer to the PT_BINARY property value.

See Also

SPropValue


SBinaryArray

The SBinaryArray structure contains an array of binary values.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SBinaryArray
{
     ULONG        cValues;
     SBinary      FAR *lpbin;
} SBinaryArray;

Members

cValues
Count of values in the array pointed to by the lpbin member.
lpbin
Pointer to an array of SBinary structures holding the binary values.

Remarks

The SBinaryArray structure is used to describe properties of type PT_MV_BINARY.

For more information on PT_MV_BINARY, see List of Property Types.

See Also

SBinary, SPropValue


SBitMaskRestriction

The SBitMaskRestriction structure describes a bitmask restriction, which is used to perform a bitwise AND operation and test the result.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SBitMaskRestriction
{
     ULONG relBMR;
     PT_LONG ulPropTag;
     ULONG ulMask;
} SBitMaskRestriction;

Members

relBMR
Relational operator describing how the mask specified in the ulMask member should be applied to the property tag. Possible values are:
BMR_EQZ
Perform a bitwise AND operation of the mask in the ulMask member with the property represented by the ulPropTag member and test for being equal to zero.
BMR_NEZ
Perform a bitwise AND operation of the mask in the ulMask member with the property represented by the ulPropTag member and test for being not equal to zero.
ulPropTag
Property tag of the property to which the bitmask is applied.
ulMask
Bitmask to apply to the property identified by ulPropTag.

Remarks

The SBitMaskRestriction structure performs a bitwise AND operation using the bitmask described in the ulMask member and the value of the property described by the ulPropTag member. If the result is zero, then BMR_EQZ is satisfied. If it's nonzero — that is, if the property value has at least one of the same bits set as ulMask — then BMR_NEZ is satisfied.

For more information on the SBitMaskRestriction structure and restrictions in general, see About Restrictions.

See Also

Restriction Structures, SRestriction


SCommentRestriction

The SCommentRestriction structure describes a comment restriction, which is used to annotate a restriction.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SCommentRestriction
{
     ULONG          cValues;
     LPSRestriction lpRes;
     LPSPropValue   lpProp;
} SCommentRestriction;

Members

cValues
Count of property values in the array pointed to by the lpProp member.
lpRes
Pointer to an SRestriction structure.
lpProp
Pointer to an array of SPropValue structures, each containing the property tag and value for a named property.

Remarks

The SCommentRestriction structure associates an object with a set of named properties. Comment restrictions are unlike other restrictions because they are not evaluated. That is, they are ignored by the IMAPITable::Restrict method. There is no effect on the rows returned by the IMAPITable::QueryRows method after an IMAPITable::Restrict call has been made.

The SCommentRestriction structure can be used to keep application-specific information with a restriction when it is saved on disk. For example, a client saving the name of a named property used in a property restriction can do so in an SCommentRestriction structure. Saving a property name is not possible in a property restriction because the associated SPropertyRestriction structure holds only the property tag.

For more information on the SCommentRestriction structure and restrictions in general, see About Restrictions.

See Also

Restriction Structures, SPropValue, SRestriction


SComparePropsRestriction

The SComparePropsRestriction structure describes a compare property restriction, which tests two properties using a relational operator.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SComparePropsRestriction
{
     ULONG relop;
     ULONG ulPropTag1;
     ULONG ulPropTag2;
} SComparePropsRestriction;

Members

relop
Relational operator to use to compare the two properties. Possible values are:
RELOP_GE
The comparison is made based on a greater or equal first value.
RELOP_GT
The comparison is made based on a greater first value.
RELOP_LE
The comparison is made based on a lesser or equal first value.
RELOP_LT
The comparison is made based on a lesser first value.
RELOP_NE
The comparison is made based on unequal values.
RELOP_RE
The comparison is made based on LIKE (regular expression) values.
RELOP_EQ
The comparison is made based on equal values.
ulPropTag1
Property tag of the first property to be compared.
ulPropTag2
Property tag of the second property to be compared.

Remarks

The comparison order is (property tag 1) (relational operator) (property tag 2). The properties to be compared must be of the same type. Attempting to compare properties of different types causes MAPI or the service provider to return the error value MAPI_E_TOO_COMPLEX from the IMAPITable method to which the structure is passed as a parameter.

The result of a compare property value restriction is undefined when one or both of the properties do not exist. When a client requires well-defined behavior for such a restriction and is not sure whether the property exists — for example, it is not a required column of a table — it should create an AND restriction to join the compare property restriction with an exist restriction. Use an SExistRestriction structure to define the exist restriction and an SAndRestriction structure to define the AND restriction.

The properties specified in the ulPropTag1 and ulPropTag2 members can be multivalued if the service provider supports it.

For more information on the SComparePropsRestriction structure and restrictions in general, see About Restrictions.

See Also

Restriction Structures, SBitMaskRestriction, SRestriction


SContentRestriction

The SContentRestriction structure describes a content restriction, which is used to limit a table view to only those rows that include a column with contents matching a search string.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SContentRestriction
{
     ULONG        ulFuzzyLevel;
     ULONG        ulPropTag;
     LPSPropValue lpProp;
} SContentRestriction;

Members

ulFuzzyLevel
Option settings defining the level of preciseness that the content restriction should enforce when checking for a match.

The lower 16 bits of the ulFuzzyLevel member apply to properties of type PT_BINARY and PT_STRING8 and must be set to one of the following values:

FL_FULLSTRING
To match, the lpProp search string must be completely contained in the property identified by ulPropTag.
FL_PREFIX
To match, the lpProp search string must appear at the beginning of the property identified by ulPropTag. The two strings should be compared only up to the length of the search string indicated by lpProp.
FL_SUBSTRING
To match, the lpProp search string must be contained anywhere within the property identified by ulPropTag.

The upper 16 bits of the ulFuzzyLevel member apply only to properties of type PT_STRING8 and can be set to the following values in any combination:

FL_IGNORECASE
The comparison should be made without considering case.
FL_IGNORENONSPACE
The comparison should ignore Unicode-defined nonspacing characters such as diacritical marks.
FL_LOOSE
The comparison should result in a match whenever possible, ignoring case and nonspacing characters.
ulPropTag
Property tag identifying the string property to be checked for occurrence of the search string.
lpProp
Pointer to a property value structure containing the string value to use as the search string.

Remarks

There are two property tags in an SContentRestriction structure: one in the ulPropTag member and the other in the ulPropTag member of the SPropValue structure pointed to by lpProp. In both tags, MAPI requires only the property type field and ignores the property identifier field. However, the two property types must match, or else the error value MAPI_E_TOO_COMPLEX is returned when the restriction is used in a call to IMAPITable::Restrict or IMAPITable::FindRow.

The values FL_FULLSTRING, FL_PREFIX, and FL_SUBSTRING are mutually exclusive. Only one of them can be set, and one of them must be set. Their meanings are fixed, and the provider must implement them exactly as defined. The provider should return MAPI_E_TOO_COMPLEX if it is unable to support these values.

The values FL_IGNORECASE, FL_IGNORENONSPACE, and FL_LOOSE are independent. Anywhere from zero to all three of them can be set. Their definitions are provided as a guideline only, and the provider is free to implement its own specific meaning of each flag. The provider should not return any error indication if it has no implementation of a specified flag.

The result of a content restriction imposed against a property is undefined when the property does not exist. When a client requires well-defined behavior for such a restriction and is not sure whether the property exists — for example, it is not a required column of a table — it should create an AND restriction to join the content restriction with an exist restriction. Use an SExistRestriction structure to define the exist restriction and an SAndRestriction structure to define the AND restriction.

For more information on the SContentRestriction structure and restrictions in general, see About Restrictions.

See Also

Restriction Structures, SPropValue, SRestriction


SCurrencyArray

The SCurrencyArray structure contains an array of currency values used to describe a property of type PT_MV_CURRENCY.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SCurrencyArray
{
     ULONG         cValues;
     CURRENCY FAR *lpcur;
} SCurrencyArray;

Members

cValues
Count of values in the array pointed to by the lpcur member.
lpcur
Pointer to an array of CURRENCY structures containing the currency values.

Remarks

For more information on PT_MV_CURRENCY, see List of Property Types.

See Also

PropValue


SDateTimeArray

The SDateTimeArray structure contains an array of time values used to describe a property of type PT_MV_SYSTIME.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SDateTimeArray
{
     ULONG         cValues;
     FILETIME FAR *lpft;
} SDateTimeArray;

Members

cValues
Count of values in the array pointed to by the lpft member.
lpft
Pointer to an array of FILETIME structures containing the time values.

Remarks

For more information on PT_MV_SYSTIME, see List of Property Types.

See Also

FILETIME, SPropValue


SDoubleArray

The SDoubleArray structure contains an array of double values used to describe a property of type PT_MV_DOUBLE.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SDoubleArray
{
     ULONG           cValues;
     double     FAR *lpdbl;
} SDoubleArray;

Members

cValues
Count of values in the array pointed to by the lpdbl member.
lpdbl
Pointer to an array of double values.

Remarks

For more information on PT_MV_DOUBLE, see List of Property Types.

See Also

SPropValue


SExistRestriction

The SExistRestriction structure describes an exist restriction which is used to test whether or not a particular property exists as a column in the table.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SExistRestriction
{
     ULONG ulReserved1;
     ULONG ulPropTag;
     ULONG ulReserved2;
} SExistRestriction;

Members

ulReserved1
Reserved; must be zero.
ulPropTag
Property tag identifying the column to be tested for existence in each row.
ulReserved2
Reserved; must be zero.

Remarks

The exist restriction is used to guarantee meaningful results for other types of restrictions that involve properties, such as property and content restrictions. When a restriction that involves a property is passed to IMAPITable::Restrict or IMAPITable::FindRow and the property does not exist, the results of the restriction are undefined. By creating an AND restriction that joins the property restriction with an exist restriction, a caller can be guaranteed accurate results.

Exist restrictions cannot be used with subobject properties — properties that have type PT_OBJECT.

For more information on the SExistRestriction structure, see About Restrictions.

See Also

Restriction Structures, SRestriction


SGuidArray

The SGuidArray structure contains an array of GUID structures used to describe a property of type PT_MV_CLSID.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SGuidArray
{
     ULONG     cValues;
     GUID      FAR *lpguid;
} SGuidArray;

Members

cValues
Count of values in the array pointed to by the lpguid member.
lpguid
Pointer to an array of GUID structures containing the class identifier values.

Remarks

For more information on PT_MV_CLSID, see List of Property Types.

See Also

GUID, SPropValue


SLargeIntegerArray

The SLargeIntegerArray structure contains an array of LARGE_INTEGER structures used to describe a property of type PT_MV_I8.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SLargeIntegerArray
{
     ULONG     cValues;
     LARGE_INTEGER      FAR *lpli;
} SLargeIntegerArray;

Members

cValues
Count of values in the array pointed to by the lpli member.
lpli
Pointer to an array of LARGE_INTEGER structures holding the integer values.

Remarks

For more information on PT_MV_18, see List of Property Types.

See Also

SPropValue


SLongArray

The SLongArray structure contains an array of values used to describe a property of type PT_MV_LONG.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SLongArray
{
     ULONG     cValues;
     LONG      FAR *lpl;
} SLongArray;

Members

cValues
Count of values in the array pointed to by the lpl member.
lpl
Pointer to an array of LONG values.

Remarks

For more information on PT_MV_LONG, see List of Property Types.

See Also

SPropValue


SLPSTRArray

The SLPSTRArray structure contains an array of string values used to described a property of type PT_MV_STRING8.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SLPSTRArray
{
     ULONG      cValues;
     LPSTR FAR *lppszA;
} SLPSTRArray;

Members

cValues
Count of values in the array pointed to by the lppszA member.
lppszA
Pointer to an array of null-terminated 8-bit character strings.

Remarks

For more information on PT_MV_STRING8, see List of Property Types.

See Also

SPropValue


SMAPIFormInfoArray

The SMAPIFormInfoArray structure contains an array of pointers to form information objects.

Quick Info

Header file: | MAPIFORM.H
Related macro: | CbMAPIFormInfoArray

typedef struct
{
     ULONG          cForms;
     LPMAPIFORMINFO aFormInfo[MAPI_DIM];
} SMAPIFormInfoArray, FAR * LPSMAPIFORMINFOARRAY;

Members

cForms
Count of pointers in the array pointed to by the aFormInfo member.
aFormInfo
Pointer to an array of pointers to form information objects.

Remarks

The SMAPIFormInfoArray structure is passed as a parameter in the following methods:

IMAPIFormMgr::ResolveMultipleMessageClasses

IMAPIFormMgr::CalcFormPropSet

IMAPIFormMgr::SelectMultipleForms

IMAPIFormContainer::ResolveMultipleMessageClasses

See Also

Form Structures


SMAPIFormProp

The SMAPIFormProp structure describes a named property used with a form.

Quick Info

Header file: MAPIFORM.H

typedef struct _SMAPIFormProp
{
     ULONG                    ulFlags;
     ULONG                    nPropType;
     MAPINAMEID               nmid;
     LPTSTR                   pszDisplayName;
     FORMPROPSPECIALTYPE      nSpecialType;
     union
     {
          struct
          {
          MAPINAMEID                 nmidIdx;
          ULONG                      cfpevAvailable;
          LPMAPIFORMPROPENUMVAL      pfpevAvailable;
          } s1;
     } u;
} SMAPIFormProp, FAR * LPMAPIFORMPROP;

Members

ulFlags
Flags used to distinguish the format of the strings in the SMAPIFormProp structure. The following flag can be set:
MAPI_UNICODE
The strings returned are in Unicode format. If MAPI_UNICODE is not set, the strings are in ANSI format.
nPropType
Type of the named property, with the most significant word set to zero.
nmid
Name for the named property, which includes a GUID structure identifying the property set and either a numeric or string value representing an interface identifier and form name.
pszDisplayName
Pointer to the display name of the named property.
nSpecialType
Value describing the type of data included in the u member. Possible values are:
FPST_VANILLA
The u member does not contain an enumeration.
FPST_ENUM_PROP
The u member contains a structure that describes an enumeration.
u
Union describing the association between the name and number of the named property. With some properties, the u member is empty. With other properties, it is represented in a structure made up of the following members:
nmidIdx
The MAPINAMEID structure containing the property set and identifier for the named property.
cfpevAvailable
Count of SMAPIFormPropEnumVal structures in the array pointed to by the pfpevAvailable member.
pfpevAvailable
Pointer to an array of SMAPIFormPropEnumVal structures, each of which holds a value for the named property.

Remarks

The SMAPIFormProp structure contains information about a form property used as part of the definitions of the IMAPIFormInfo interface; nSpecialType contains a tag that applies to the u union that is part of SMAPIFormProp.

See Also

Form Structures, MAPINAMEID, SMAPIFormPropEnumVal


SMAPIFormPropArray

The SMAPIFormPropArray structure contains an array of SMAPIFormProp structures.

Quick Info

Header file: | MAPIFORM.H
Related macro: | CbMAPIFormPropArray

typedef struct
{
     ULONG         cProps;
     ULONG         ulPad;
     SMAPIFormProp aFormProp[MAPI_DIM];
} SMAPIFormPropArray, FAR * LPMAPIFORMPROPARRAY;

Members

cProps
Count of named properties in the array in the aFormProp member.
ulPad
Eight bytes of padding used to ensure proper alignment.
aFormProp
Array of form properties.

Remarks

The SMAPIFormPropArray structure is passed as a parameter to the following methods:

IMAPIFormInfo::CalcFormPropSet

IMAPIFormMgr::CalcFormPropSet

IMAPIFormContainer::CalcFormPropSet

See Also

Form Structures, CbMAPIFormPropArray, SMAPIFormProp


SMAPIFormPropEnumVal

The SMAPIFormPropEnumVal structure maps an enumerated integer value to a display name for that value.

Quick Info

Header file: MAPIFORM.H

typedef struct _SMAPIFormPropEnumVal
{
     LPTSTR         pszDisplayName;
     ULONG          nVal;
} SMAPIFormPropEnumVal;

Members

pszDisplayName
String containing the display name for the value specified in the nVal member.
nVal
An enumeration value for the display name pointed to by the pszDisplayName member.

Remarks

When a user selects a display name from a form, the name's corresponding enumeration value is stored using the IMAPIProp interface implementation that is associated with the form.

See Also

Form Structures, SMAPIFormProp, SPropValue


SMAPIVerb

The SMAPIVerb structure describes a MAPI verb.

Quick Info

Header file: MAPIFORM.H

typedef struct
{
     ULONG   lVerb;
     LPTSTR  szVerbname;
     DWORD   fuFlags;
     DWORD   grfAttribs;
     ULONG   ulFlags;                 /* Either 0 or MAPI_UNICODE */
} SMAPIVerb, FAR * LPMAPIVERB;

Members

lVerb
Code representing the verb that is passed to IMAPIForm::DoVerb. Standard verbs are defined in the header file EXCHFORM.H.
szVerbname
Display name of the verb as it appears on the form menu.
fuFlags
Flags for the verb.
grfAttribs
Attributes of the verb.
ulFlags
Flag indicating the format of the verb's display name. The following flag can be set:
MAPI_UNICODE
The display name is in Unicode format. If the MAPI_UNICODE flag is not set, the display name is in ANSI format.

Remarks

The SMAPIVerb structure is passed as a parameter in the following methods:

IMAPIFormContainer::ResolveMultipleMessageClasses

IMAPIFormMgr::ResolveMultipleMessageClasses

See Also

Form Structures, CbMessageClassArray


SMAPIVerbArray

The SMAPIVerbArray structure contains an array of SMAPIVerb structures describing MAPI verbs.

Quick Info

Header file: | MAPIFORM.H
Related macro: | CbMAPIVerbArray

typedef struct
{
     ULONG     cMAPIVerb;
     SMAPIVerb aMAPIVerb[MAPI_DIM];
} SMAPIVerbArray, FAR * LPMAPIVERBARRAY;

Members

cForms
Count of verbs in the array.
aFormInfo
Array of MAPI verbs.

Remarks

The SMAPIVerbArray structure is passed as a parameter in the IMAPIFormInfo::CalcVerbSet method.

See Also

Form Structures, SMAPIVerb


SMessageClassArray

The SMessageClassArray structure contains an array of pointers to message class strings.

Quick Info

Header file: | MAPIDEFS.H
Related macro: | CbMessageClassArray

typedef struct
{
     ULONG   cValues;
     LPCSTR  aMessageClass[MAPI_DIM];
} SMessageClassArray, FAR * LPSMESSAGECLASSARRAY;

Members

cValues
Count of message class string pointers in the array.
aMessageClass
Array of pointers to message class strings.

Remarks

The SMessageClassArray structure is passed as a parameter in the following methods:

IMAPIFormContainer::ResolveMultipleMessageClasses

IMAPIFormMgr::ResolveMultipleMessageClasses

See Also

Form Structures


SNotRestriction

The SNotRestriction structure describes a NOT restriction, which is used to apply a logical NOT operation to a restriction.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SNotRestriction
{
     ULONG           ulReserved;
     LPSRestriction  lpRes;
} SNotRestriction;

Members

ulReserved
Reserved; must be zero.
lpRes
Pointer to the restriction structure describing the restriction to be joined with the logical NOT operator.

Remarks

For more information on the SNotRestriction structure, see About Restrictions.

See Also

Restriction Structures, SRestriction


SOrRestriction

The SOrRestriction structure describes an OR restriction which is used to apply a logical OR operation to a restriction.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SOrRestriction
{
     ULONG           cRes;
     LPSRestriction  lpRes;
} SOrRestriction;

Members

cRes
Count of structures in the array pointed to by the lpRes member.
lpRes
Pointer to the SRestriction structure describing the restriction to be joined using the logical OR operation.

Remarks

For more information on the SOrRestriction structure, see About Restrictions.

See Also

Restriction Structures, SRestriction


SPropAttrArray

The SPropAttrArray structure contains a list of attributes for properties of an object.

Quick Info

Header file: | IMESSAGE.H
Related macros: | CbNewSPropAttrArray CbSPropAttrArray

typedef struct
{
     ULONG     cValues;
     ULONG     aPropAttr[MAPI_DIM];
} SPropAttrArray, FAR *LPSPropAttrArray;

Members

cValues
Count of property attributes in the aPropAttr member.
aPropAttr
An array of property attributes. Valid values for attributes are:
PROPATTR_MANDATORY
PROPATTR_READABLE
PROPATTR_WRITEABLE
PROPATTR_NOT_PRESENT

Remarks

The SPropAttrArray structure is used only by property data objects — objects that implement the IPropData interface — and by MAPI's implementation of IMessage that is based on structured storage.

See Also

Property Structures


SPropertyRestriction

The SPropertyRestriction structure describes a property restriction which is used to match a constant with the value of a property.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SPropertyRestriction
{
     ULONG        relop;
     ULONG        ulPropTag;
     LPSPropValue lpProp;
} SPropertyRestriction;

Members

relop
Relational operator to be used in the search. Possible values are:
RELOP_GE
The comparison is made based on a greater or equal first value.
RELOP_GT
The comparison is made based on a greater first value.
RELOP_LE
The comparison is made based on a lesser or equal first value.
RELOP_LT
The comparison is made based on a lesser first value.
RELOP_NE
The comparison is made based on unequal values.
RELOP_RE
The comparison is made based on LIKE (regular expression) values.
RELOP_EQ
The comparison is made based on equal values.
ulPropTag
Property tag identifying the property to be compared.
lpProp
Pointer to an SPropValue structure containing the constant value to be used in the comparison.

Remarks

There are two property tags in an SPropertyRestriction structure: one in the ulPropTag member and the other in the ulPropTag member of the SPropValue structure pointed to by lpProp. In both tags, MAPI requires only the property type field and ignores the property identifier field. However, the two property types must match, or else the error value MAPI_E_TOO_COMPLEX is returned when the restriction is used in a call to IMAPITable::Restrict or IMAPITable::FindRow.

The comparison order is (property value) (relational operator) (constant value).

When a property restriction is passed to IMAPITable::Restrict or IMAPITable::FindRow and the target property does not exist, the results of the restriction are undefined. By creating an AND restriction that joins the property restriction with an exist restriction, a caller can be guaranteed accurate results. Use an SExistRestriction structure to define the exist restriction and an SAndRestriction structure to define the AND restriction.

Multivalued properties can be used in property restrictions if the service provider implementing the table supports them. If supported, multivalued property tags can be used anywhere single-valued property tags can be used. They can be used in IMAPIProp::SetProps, IMAPIProp::GetProps, IMAPITable::SetColumns, IMAPITable::SortTable, and IMAPITable::Restrict.

For more information on the SPropertyRestriction structure, see About Restrictions.

See Also

Restriction Structures, SPropValue, SRestriction


SPropProblem

The SPropProblem structure describes an error relating to an operation involving a property.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SPropProblem
{
     ULONG     ulIndex;
     ULONG     ulPropTag;
     SCODE     scode;
} SPropProblem, FAR *LPSPropProblem;

Members

ulIndex
An index in an array of property tags.
ulPropTag
Property tag for the property with the error.
scode
Error value describing the problem with the property. This value can be any MAPI SCODE value.

Remarks

An array of SPropProblem structures is returned from the following methods:

IMAPISupport::DoCopyTo

IMAPISupport::DoCopyProps

IMAPIProp::DeleteProps

IMAPIProp::SetProps

IMAPIProp::CopyProps

IMAPIProp::CopyTo

IPropData::HrAddObjProps

An SPropProblem structure contains an SCODE error value that is a result of an operation attempting to modify or delete a MAPI property.

For more information on how the SPropProblem structure works with errors related to properties, see Named Properties.

See Also

Property Structures, SCODE, SPropProblemArray


SPropProblemArray

The SPropProblemArray structure contains an array of one or more SPropProblem structures.

Quick Info

Header file: | MAPIDEFS.H
Related macros: | CbNewSPropProblemArray CbSPropProblemArray SizedSPropProblemArray

typedef struct _SPropProblemArray
{
     ULONG          cProblem;
     SPropProblem   aProblem[MAPI_DIM];
} SPropProblemArray, FAR *LPSPropProblemArray;

Members

cProblem
Count of SPropProblem structures in the array indicated by the aProblem member.
aProblem
Array of SPropProblem structures, each describing a property error.

Remarks

For more information on how the SPropProblem and SPropProblemArray structures work with errors related to properties, see Named Properties.

See Also

Property Structures, SCODE, SPropProblem


SPropTagArray

The SPropTagArray structure contains an array of property tags.

Quick Info

Header file: | MAPIDEFS.H
Related macros: | CbNewSPropTagArray CbSPropTagArray SizedSPropTagArray

typedef struct _SPropTagArray
{
     ULONG      cValues;
     ULONG      aulPropTag[MAPI_DIM];
} SPropTagArray, FAR *LPSPropTagArray;

Members

cValues
Count of property tags in the array indicated by the aulPropTag member.
aulPropTag
Array of property tags.

Remarks

A property tag is a 32-bit unsigned integer made up of two parts:

  • An identifier in the high-order 16 bits.
  • A type in the low-order 16 bits.

The identifier is a numeric value within a particular range. MAPI defines ranges for identifiers to describe what the property is used for and who is responsible for maintaining it. MAPI defines constraints for each of the property tags that it supports in the MAPITAGS.H header file.

The type indicates the format for the property's value. MAPI defines constants for each of the property types that it supports in the MAPIDEFS.H header file.

For more information about property tags and their components, see one of the following topics:

About Property Tags

About Property Identifiers

About Property Types

For a complete list of the single-valued and multivalued property types, see the appendix, Property Identifiers and Types.

See Also

Property Structures


SPropValue

The SPropValue structure describes a MAPI property.

Quick Info

Header file: | MAPIDEFS.H
Related macros: | CHANGE_PROP_TYPE MVI_PROP PROP_ID PROP_TAG PROP_TYPE

typedef struct _SPropValue
{
     ULONG     ulPropTag;
     ULONG     dwAlignPad;
     union _PV  Value;
} SPropValue, FAR *LPSPropValue;

Members

ulPropTag
Property tag for the property. Property tags are 32-bit unsigned integers consisting of the property's unique identifier in the high-order 16 bits and the property's type in the low-order 16 bits.
dwAlignPad
Reserved for MAPI; do not use.
Value
Union of data values, the specific value dictated by the property type. The following table lists for each property type, the member of the union that should be used and its associated data type.
Property type | Value | Data type of Value
PT_I2 or PT_SHORT | i | short int
PT_I4 or PT_LONG (signed) | I | LONG
PT_I4 or PT_LONG (unsigned) | ul | ULONG
PT_R4 or PT_FLOAT | flt | float
PT_R8 or PT_DOUBLE | dbl | double
PT_BOOLEAN | b | unsigned short int
PT_CURRENCY | cur | CURRENCY
PT_APPTIME | at | double
PT_SYSTIME | ft | FILETIME
PT_STRING8 | lpszA | LPSTR
PT_BINARY | bin | BYTE [array]
PT_UNICODE | lpszW | LPWSTR
PT_CLSID | lpguid | LPGUID
PT_I8 or PT_LONGLONG | li | LARGE_INTEGER
PT_MV_I2 | MVi | SShortArray
PT_MV_LONG | MVI | SLongArray
PT_MV_R4 | MVflt | SRealArray
PT_MV_DOUBLE | MVdbl | SDoubleArray
PT_MV_CURRENCY | MVcur | SCurrencyArray
PT_MV_APPTIME | MVat | SAppTimeArray
PT_MV_SYSTIME | MVft | SDateTimeArray
PT_MV_BINARY | MVbin | SBinaryArray
PT_MV_STRING8 | MVszA | SLPSTRArray
PT_MV_UNICODE | MVszW | SWStringArray
PT_MV_CLSID | MVguid | SGuidArray
PT_MV_I8 | MVli | SLargeIntegerArray
PT_ERROR | err | SCODE
PT_NULL or PT_OBJECT | x | LONG

Remarks

The ulPropTag member is made up of two parts:

  • An identifier in the high-order 16 bits.
  • A type in the low-order 16 bits.

The identifier is a numeric value within a particular range. MAPI defines ranges for identifiers to describe what the property is used for and who is responsible for maintaining it. MAPI defines constraints for each of the property tags that it supports in the MAPITAGS.H header file.

The type indicates the format for the property's value. MAPI defines constants for each of the property types that it supports in the MAPIDEFS.H header file.

For a complete list of the valid property ranges for identifiers and property types, see the Property Identifiers and Types appendix.

The dwAlignPad member is used as padding to ensure proper alignment on computers that require 8-byte alignment for 8-byte values. Developers who write code on such computers should use memory allocation routines that allocate the SPropValue arrays on 8-byte boundaries.

For more information, see About Property Types and Updating Properties.

See Also

Property Structures


SRealArray

The SRealArray structure contains an array of float values used to describe a property of type PT_MV_R4.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SRealArray
{
     ULONG     cValues;
     float     FAR *lpflt;
} SRealArray;

Members

cValues
Count of values in the array pointed to by the lpflt member.
lpflt
Pointer to an array of float values.

Remarks

For more information on the PT_MV_R4 property type, see List of Property Types.

See Also

SPropValue


SRestriction

The SRestriction structure describes a filter for limiting the view of a table to particular rows.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SRestriction
{
     ULONG     rt;
     union
     {
          SComparePropsRestriction    resCompareProps;
          SAndRestriction             resAnd;
          SOrRestriction              resOr;
          SNotRestriction             resNot;
          SContentRestriction         resContent;
          SPropertyRestriction        resProperty;
          SBitMaskRestriction         resBitMask;
          SSizeRestriction            resSize;
          SExistRestriction           resExist;
          SSubRestriction             resSub;
          SCommentRestriction         resComment;
     } res;
} SRestriction;

Members

rt
The restriction type. Possible values are:
RES_AND
SRestriction structure describes an AND restriction, which applies a bitwise AND operation to a restriction.
RES_BITMASK
SRestriction structure describes a bitmask restriction, which applies a bitmask to a property value.
RES_COMMENT
SRestriction structure describes a comment restriction, which associates a comment with a restriction.
RES_COMPAREPROPS
SRestriction structure describes a compare properties restriction, which compares two property values.
RES_CONTENT
SRestriction structure describes a content restriction, which searches a property value for specific content.
RES_EXIST
SRestriction structure describes an exist restriction, which determines if a property is supported.
RES_NOT
SRestriction structure describes a NOT restriction, which applies a logical NOT operation to a restriction.
RES_OR
SRestriction structure describes an OR restriction, which applies a logical OR operation to a restriction.
RES_PROPERTY
SRestriction structure describes a property restriction, which determines if a property value matches a particular value.
RES_SIZE
SRestriction structure describes a size restriction, which determines if a property value is a particular size.
RES_SUBRESTRICTION
SRestriction structure describes a subobject restriction, which applies a restriction to a message's attachments or recipients.
res
Union of restriction structures describing the filter to be applied. The specific structure included in the res member depends on the value of the rt member. The mapping between restriction type and structure is listed in the following table.

Restriction type | Restriction structure
RES_AND | SAndRestriction
RES_BITMASK | SBitMaskRestriction
RES_COMMENT | SCommentRestriction
RES_COMPAREPROPS | SComparePropsRestriction
RES_CONTENT | SContentRestriction
RES_EXIST | SExistRestriction
RES_NOT | SNotRestriction
RES_OR | SOrRestriction
RES_PROPERTY | SPropertyRestriction
RES_SIZE | SSizeRestriction
RES_SUBRESTRICTION | SSubRestriction

Remarks

Clients use an SRestriction structure to limit the number and type of rows in their view of a table and to search for specific messages in a folder. To impose the limitation on a table, clients call either IMAPITable::Restrict or IMAPITable::FindRow. To impose the limitation on a folder, clients call the folder's IMAPIContainer::SetSearchCriteria method.

For information about using restrictions with tables, see About Restrictions. For information about using restrictions with folders, see Search-Results Folders.

See Also

Restriction Structures, SAndRestriction, SBitMaskRestriction, SCommentRestriction, SComparePropsRestriction, SContentRestriction, SExistRestriction, SNotRestriction, SOrRestriction, SPropertyRestriction, SSizeRestriction, SSubRestriction, IMAPIContainer::SetSearchCriteria, IMAPITable::FindRow, IMAPITable::Restrict


SRow

The SRow structure describes a row from a table containing selected properties for a specific object.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SRow
{
     ULONG         ulAdrEntryPad;
     ULONG         cValues;
     LPSPropValue  lpProps;
} SRow, FAR *LPSRow;

Members

ulAdrEntryPad
Padding bytes to properly align the property values pointed to by the lpProps member.
cValues
Count of property values pointed to by lpProps.
lpProps
Pointer to an array of SPropValue structures that describe the property values for the columns in the row.

Remarks

An SRow structure describes a row in a table. An SRow structure is included in the TABLE_NOTIFICATION structure that accompanies a table notification and is used in the following:

IAddrBook::GetSearchPath

IAddrBook::SetSearchPath

IMAPITable::QueryRows

IMAPITable::ExpandRow

ITableData (many methods)

FBadRowSet

FreeProws

HrQueryAllRows

When more than one row needs to be described, an SRowSet structure is used. An SRowSet structure contains an array of SRow structures and a count of structures in the array.

The following illustration shows the relationship between an SRow and an SRowSet data structure.

SRow structures are defined the same as ADRENTRY structures so that a row of a recipient table and an entry in an address list can be treated the same. For information about how the memory for SRow structures should be allocated, see Managing Memory for ADRLIST and SRowSet Structures.

See Also

Table Structures, ITableData::HrQueryRow, TABLE_NOTIFICATION,

SPropValue, SRowSet


SRowSet

The SRowSet structure contains an array of SRow structures, each SRow structure describing a row from a table.

Quick Info

Header file: | MAPIDEFS.H
Related macros: | CbNewSRowSet CbSRowSet SizedSRowSet

typedef struct _SRowSet
{
     ULONG   cRows;
     SRow    aRow[MAPI_DIM];
} SRowSet, FAR *LPSRowSet;

Members

cRows
Count of SRow structures in the aRow member.
aRow
Array of SRow structures, one for each row in the table.

Remarks

An SRowSet structure is used to describe multiple rows of data from a table. SRowSet structures are used in the methods of the IMAPITable interface, such as QueryRows, the ITableData interface, the IAddrBook interface, and the following functions:

HrQueryAllRows

FBadRowSet

FreeProws

SRowSet structures are defined the same as ADRLIST structures to allow the rows of a recipient table and the entries in an address list to be treated the same. Both SRowSet structures and ADRLIST structures can be passed to methods such as IMessage::ModifyRecipients and IAddrBook::Address.

Also, the rules for memory allocation for SRowSet structures are the same as for ADRLIST structures. To summarize, each SPropValue structure in the array pointed to by the lpProps member of each row in the row set must be allocated separately using MAPIAllocateBuffer. Each property value structure also must be deallocated using MAPIFreeBuffer prior to the deallocation of its SRowSet structure so that pointers to the allocated SPropValue structures are not lost. A row's allocated memory can then be preserved and reused outside the context of the SRowSet structure.

For more information about how the memory for SRowSet structures should be allocated, see Managing Memory for ADRLIST and SRowSet Structures.

See Also

Table Structures


SShortArray

The SShortArray structure contains an array of unsigned integer values used to describe a property of type PT_MV_SHORT.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SShortArray
{
     ULONG              cValues;
     short int     FAR *lpi;
} SShortArray;

Members

cValues
Count of values in the array pointed to by the lpi member.
lpi
Pointer to an array of unsigned integer values.

Remarks

For more information on PT_MV_SHORT and other property types, see List of Property Types.

See Also

SPropValue


SSizeRestriction

The SSizeRestriction structure describes a size restriction which is used to test the size of a property value.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SSizeRestriction
{
     ULONG relop;
     ULONG ulPropTag;
     ULONG cb;
} SSizeRestriction;

Members

relop
Relational operator used in the size comparison. Possible values are:
RELOP_GE
The comparison is made based on a greater or equal first value.
RELOP_GT
The comparison is made based on a greater first value.
RELOP_LE
The comparison is made based on a lesser or equal first value.
RELOP_LT
The comparison is made based on a lesser first value.
RELOP_NE
The comparison is made based on unequal values.
RELOP_RE
The comparison is made based on LIKE (regular expression) values.
RELOP_EQ
The comparison is made based on equal values.
ulPropTag
Property tag identifying the property to test.
cb
Count of bytes in the property value.

Remarks

For a general discussion of how restrictions work, see About Restrictions.

See Also

Restriction Structures, SRestriction


SSortOrder

The SSortOrder structure defines how to sort rows of a table, describing the column to use as the sort key and the direction of the sort.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SSortOrder
{
     ULONG ulPropTag;
     ULONG ulOrder;
} SSortOrder, FAR *LPSSortOrder;

Members

ulPropTag
Property tag identifying the sort key or, for a categorized sort, the category column.
ulOrder
The order in which the data is to be sorted. Possible values are:
TABLE_SORT_ASCEND
The table should be sorted in ascending order.
TABLE_SORT_COMBINE
The sort operation should create a category that combines the property identified as the sort key column in the ulPropTag member with the sort key column specified in the previous SSortOrder structure.

TABLE_SORT_COMBINE can only be used when the SSortOrder structure is being used as an entry in an SSortOrderSet structure to specify multiple sort orders for a categorized sort. TABLE_SORT_COMBINE cannot be used in the first SSortOrder structure in an SSortOrderSet structure.

TABLE_SORT_DESCEND
The table should be sorted in descending order.

Remarks

An SSortOrder structure is used to describe how to perform either a standard sort operation or a categorized sort operation. SSortOrder structures are typically combined into an SSortOrderSet structure to describe multiple sort keys and directions. SSortOrderSet structures are used in the following:

ITableData::HrGetView

IMAPIFolder::SaveContentsSort

IMAPITable::QuerySortOrder

IMAPITable::SortTable

FBadSortOrderSet

HrQueryAllRows

The range of allowable columns in a table that can be used as a sort key depends on the provider. Columns that are part of the current column set can always be used as sort keys. However, each provider determines whether or not sort keys can be defined with available columns that are not in the current column set. An available column is a column that is returned from IMAPITable::QueryColumns when the TBL_ALL_COLUMNS flag is set.

The ulOrder member indicates both directional order and categorization information. Rows can be sorted in either an ascending or descending sequence with all NULL entries placed last.

The TABLE_SORT_COMBINE value indicates that the column specified in ulPropTag should be combined with the previous category column to form a composite category. That is, instead of categorizing on unique values of individual columns, TABLE_SORT_COMBINE allows categorization on unique values of a combination of columns. A single category could be defined, for example, to group messages received from a particular sender on a particular subject. Using TABLE_SORT_COMBINE reduces the number of category rows which are displayed.

Sorting on multivalued columns is not universally supported by all table implementations. If supported, apply the MV_FLAG using the MVI_PROP macro to the property tag in the ulPropTag member to identify the sort key as a multivalued column. Sorting on a multivalued column is based on using the individual values.

For more information about standard and categorized sorting, see Sorting and Categorization.

See Also

Table Structures, SSortOrderSet


SSortOrderSet

The SSortOrderSet structure defines a collection of sort keys for a table to be used for standard or categorized sorting.

Quick Info

Header file: | MAPIDEFS.H
Related macros: | CbNewSSortOrderSet CbSSortOrderSet SizedSSortOrderSet

typedef struct _SSortOrderSet
{
     ULONG      cSorts;
     ULONG      cCategories;
     ULONG      cExpanded;
     SSortOrder aSort[MAPI_DIM];
} SSortOrderSet, FAR *LPSSortOrderSet;

Members

cSorts
Count of SSortOrder structures that are included in the aSort member.
cCategories
Count of columns that are designated as category columns. Possible values range from zero, which indicates a noncategorized or standard sort, to the number indicated by the cSorts member.
cExpanded
Count of categories that start in an expanded state, where all of the rows that apply to the category are visible in the table view. Possible values range from 0 to the number indicated by cCategories.
aSort
Array of SSortOrder structures, each defining a sort order.

Remarks

An SSortOrderSet structure is used for defining multiple sort orders for standard and categorized sorting.

Each SSortOrderSet structure contains at least one SSortOrder structure defining the direction of the sort and the column to be used as the sort key. For categorized sorting, this column is used as the category. When the value of the cSorts member exceeds the value of the cCategories member, indicating that there are more sort keys than categories, categories are created from the columns that appear first in the SSortOrder array.

For example, if cSorts is set to 3 and cCategories is set to 2, the columns described by the ulPropTag member of the first two entries in the SSortOrder array are used as the category columns. The first entry serves as the top-level category grouping; the second entry as the secondary grouping. All of the rows that match the two category columns are sorted using the sort key defined in the third entry.

The following illustration shows how a contents table appears to a user in its expanded state. As in the previous example, the contents table is sorted using a categorized sort, with two columns acting as category columns and a third column as a standard sort key.

The cExpanded member specifies the number of categories that are initially expanded. When there are multiple categories, the table implementation begins with the first column to be designated as a category and continues in sequential order with the subsequent category columns until the number of cCategories has been exceeded. If there are more category columns than there are expanded columns, the category columns are collapsed. If cExpanded is equal to zero, only the top level heading row is available to the table user for display. If cExpanded is equal to one less than the number of categories, then all of the heading rows but none of the leaf rows are available. If cExpanded is equal to the number of categories, then the table is fully expanded.

For more information about standard and categorized sorting, see Sorting and Categorization.

See Also

Table Structures, IMAPITable::ExpandRow, IMAPITable::CollapseRow


SSubRestriction

The SSubRestriction structure describes a subobject restriction which is used to filter the rows of a message's attachment or recipient table.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SSubRestriction
{
     ULONG          ulSubObject;
     LPSRestriction lpRes;
} SSubRestriction;

Members

ulSubObject
Type of subobject to serve as the target for the restriction. Possible values are:
PR_MESSAGE_RECIPIENTS
Apply the restriction to a message's recipient table.
PR_MESSAGE_ATTACHMENTS
Apply the restriction to a message's attachment table.
lpRes
Pointer to an SRestriction structure.

Remarks

Subobject restrictions are not supported by all tables. Typically, only folder contents tables and search-results folders support them. Subobject restrictions are used, for example, to find a message that has a particular type of attachment or recipient.

If an implementation does not support subobject restrictions, it returns MAPI_E_TOO_COMPLEX from its IMAPITable::Restrict or IMAPITable::FindRow methods.

For a general discussion of how restrictions work, see About Restrictions.

See Also

Restriction Structures, SRestriction


STATUS_OBJECT_NOTIFICATION

The STATUS_OBJECT_NOTIFICATION structure describes a status object that has been affected by a change.

Quick Info

Header file: MAPIDEFS.H

typedef struct
{
     ULONG         cbEntryID;
     LPENTRYID     lpEntryID;
     ULONG         cValues;
     LPSPropValue  lpPropVals;
} STATUS_OBJECT_NOTIFICATION;

Members

cbEntryID
Count of bytes in the entry identifier pointed to by the lpEntryID member.
lpEntryID
Pointer to the entry identifier of the changed status object.
cValues
Count of SPropValue structures in the array pointed to by the lpPropVals member.
lpPropVals
Pointer to an array of SPropValue structures that describe the properties of the changed status object.

Remarks

The STATUS_OBJECT_NOTIFICATION structure is one of the members of the union of structures included in the info member of the NOTIFICATION structure. The STATUS_OBJECT_NOTIFICATION structure is included with a status object notification — a notification for an event of type fnevStatusObjectModified. Status object notification is an internal MAPI notification; clients and service providers cannot register for it and service providers cannot generate it.

For more information about notification, see the topics described in the following table.

Topic | Description
Event Notification in MAPI | General overview of notification and notification events.
Handling Notifications | Discussion of how clients should handle notifications.
Supporting Event Notification | Discussion of how service providers can use the IMAPISupport method to generate notifications.

See Also

Notification Structures, NOTIFICATION, SPropValue


STnefProblem

The STnefProblem structure contains information about a property or attribute processing problem that occurred during the encoding or decoding of a Transport-Neutral Encapsulation Format (TNEF) stream.

Quick Info

Header file: TNEF.H

typedef struct _STnefProblem
{
     ULONG     ulComponent;
     ULONG     ulAttribute;
     ULONG     ulPropTag;
     SCODE     scode;
} STnefProblem;

Members

ulComponent
The type of processing during which the problem occurred. If the problem occurred during message processing, the ulComponent member is set to zero. If the problem occurred during attachment processing, ulComponent is set equal to the corresponding attachment's PR_ATTACH_NUM value.
ulAttribute
Attribute associated with the property indicated by the ulPropTag member or, when the TNEF processing problem arises while decoding an encapsulation block, one of the following values:
attMAPIProps
Message level
attAttachment
Attachment level
ulPropTag
Property tag of the property that caused the TNEF processing problem, except when the problem arises while decoding an encapsulation block, in which case ulPropTag is set to zero.
scode
Error value indicating the problem encountered during processing.

Remarks

If an STnefProblem structure is not generated during the processing of an attribute or property, the application can continue under the assumption that the processing of that attribute or property succeeded. The only exception occurs when the problem arose during decoding of an encapsulation block. In this case, the decoding of the component corresponding to the block is halted and decoding is continued in another component.

See Also

TNEF Structures, STnefProblemArray


STnefProblemArray

The STnefProblemArray structure contains an array of STnefProblem structures describing one or more processing problems that occurred during the encoding or decoding of a Transport-Neutral Encapsulation Format (TNEF) stream.

Quick Info

Header file: TNEF.H

typedef struct _STnefProblemArray
{
     ULONG           cProblem;
     STnefProblem    aProblem[MAPI_DIM];
}STnefProblemArray, FAR * LPSTnefProblemArray

Members

cProblem
Count of elements in the array specified in the aProblem member.
aProblem
Array of STnefProblem structures. Each structure contains information about a property or attribute processing problem.

Remarks

If a problem occurs during attribute or property processing, an output parameter in the ITnef::ExtractProps method and in the ITnef::Finish method each receive a pointer to an STnefProblemArray structure and ExtractProps and Finish each return the value MAPI_W_ERRORS_RETURNED. This error value indicates that a problem arose during processing and an STnefProblemArray structure was generated.

If an STnefProblem structure is not generated during the processing of an attribute or property, the client application can continue under the assumption that the processing of that attribute or property succeeded. The only exception occurs when the problem arose during decoding of an encapsulation block. If the error occurred during this decoding, MAPI_E_UNABLE_TO_COMPLETE can be returned as the SCODE in the structure. In this case, the decoding of the component corresponding to the block is halted and decoding is continued in another component.

See Also

TNEF Structures, ITnef::ExtractProps, ITnef::Finish, STnefProblem


SWStringArray

The SWStringArray structure contains an array of character strings used to describe a property of type PT_MV_UNICODE.

Quick Info

Header file: MAPIDEFS.H

typedef struct _SWStringArray
{
     ULONG           cValues;
     LPWSTR     FAR *lppszW;
} SWStringArray;

Members

cValues
Count of strings in the array pointed to by the lppszW member.
lppszW
Pointer to an array of null-terminated Unicode character strings.

Remarks

For more information on PT_MV_UNICODE, see List of Property Types.

See Also

SPropValue


TABLE_NOTIFICATION

The TABLE_NOTIFICATION structure describes a row in a table that has been affected by some type of event, such as a change or an error, causing a table notification to be generated.

Quick Info

Header file: MAPIDEFS.H

typedef struct _TABLE_NOTIFICATION
{
     ULONG        ulTableEvent;
     HRESULT      hResult;
     SPropValue   propIndex;
     SPropValue   propPrior;
     SRow         row;
} TABLE_NOTIFICATION;

Members

ulTableEvent
Bitmask of flags used to represent the table event type. The following flags can be set:
TABLE_CHANGED
Indicates at a high level that something about the table has changed. The table's state is as it was before the event, meaning that all PR_INSTANCE_KEY properties, bookmarks, current positioning, and user interface selections are still valid.

Handle this event by re-reading the entire table. Service providers that do not want to implement "rich" table notifications simply send TABLE_CHANGED events rather than more detailed events to indicate a particular type of change.

TABLE_ERROR
An error has occurred, usually during the processing of an asynchronous operation. Errors during the processing of the following methods can generate this event:

IMAPITable::SortTable

IMAPITable::SetColumns

IMAPITable::Restrict

After receiving a TABLE_ERROR event, a client cannot rely on the accuracy of the table contents. Also, pending notifications about other changes might be lost.

The IMAPITable::GetLastError method might not provide any further information about the error because it was generated at some previous point, not necessarily from the last method call.

TABLE_RELOAD
The data in the table should be reloaded. Service providers send TABLE_RELOAD when, for example, the underlying data is stored in a database and the database is replaced.

Handle this event by assuming that nothing about the table is still valid and by re-reading the entire table. All bookmarks, instance keys, status and positioning information are invalid.

TABLE_RESTRICT_DONE
A restriction operation initiated with an IMAPITable::Restrict method call has completed.
TABLE_ROW_ADDED
A new row has been added to the table and the corresponding object saved. TABLE_ROW_ADDED events are generated after a call to the object's IMAPIProp::SaveChanges method.
TABLE_ROW_DELETED
A row has been removed from the table. The propPrior member is set to NULL.
TABLE_ROW_MODIFIED
A row has been changed. The row member contains the affected properties for the row. Multiple TABLE_ROW_MODIFIED events are sent in the order that they appear in the table view.

TABLE_ROW_MODIFIED events are sent after changes to the corresponding object have been committed with a call to the object's IMAPIProp::SaveChanges method. If the modified row is now the first row in the table, the value of the property tag in the propPrior member is PR_NULL.

TABLE_SETCOL_DONE
A column setting operation initiated with an IMAPITable::SetColumns method call has competed.
TABLE_SORT_DONE
A table sorting operation initiated with an IMAPITable::SortTable method call has competed.
hResult
HRESULT value for the error that has occurred, if the ulTableEvent member is set to TABLE_ERROR.
propIndex
SPropValue structure for the PR_INSTANCE_KEY property of the affected row.
propPrior
SPropValue structure for the PR_INSTANCE_KEY property of the row preceding the affected one. If the affected row is the first row in the table, propPrior must be set to PR_NULL and not zero. Zero is not a valid property tag.
row
SRow structure describing the affected row. This structure is filled for all table notification events. For table notification events that do not pass row data, the cValues member of the SRow structure is set to zero and the lpProps member is set to NULL.

Because this SRow structure is read-only; clients must make a copy of it if they want to make modifications. The ScDupPropSet function can be used to make the copy.

Remarks

The TABLE_NOTIFICATION structure is one of the members of the union of structures included in the info member of the NOTIFICATION structure. The info member includes a TABLE_NOTIFICATION structure when the ulEventType member of the structure is set to fnevTableModified.

The order and type of columns in the row member reflect the order and type that was in effect at the time that the notification was generated, which is not necessarily the same as when the notification was delivered.

For more information about notification, see the topics described in the following table.

Topic | Description
Event Notification in MAPI | General overview of notification and notification events.
Handling Notifications | Discussion of how clients should handle notifications.
Supporting Event Notification | Discussion of how service providers can use the IMAPISupport method to generate notifications.

Because table notifications are asynchronous, it is possible to receive notification of an added row after learning about the addition through another means. It is possible to receive a TABLE_ERROR event when there is an error in an IMAPITable::Sort, IMAPITable::Restrict, or IMAPITable::SetColumns method or when an underlying process attempts to update a table with, for example, new or modified rows.

See Also

Notification Structures, IMAPITable::Restrict, IMAPITable::SetColumns, NOTIFICATION, SPropValue, SRow


Macros Related to Structures

The following alphabetized entries describe the macros related to MAPI structures. For more detailed information, cross references to other publications or to other topics in this documentation are also included.


CbADRLIST

The CbADRLIST macro computes the number of bytes in an existing ADRLIST structure.

Quick Info

Header file: | MAPIDEFS.H
Related structure | ADRLIST

CbADRLIST (_lpadrlist)

Parameters

_lpadrlist
Pointer to the existing ADRLIST structure.


CbFLATENTRY

The CbFLATENTRY macro computes the number of bytes in an existing FLATENTRY structure.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | FLATENTRY

CbFLATENTRY (_lpentry)

Parameters

_lpentry
Pointer to the existing FLATENTRY structure.


CbFLATENTRYLIST

The CbFLATENTRYLIST macro computes the number of bytes in an existing FLATENTRYLIST structure.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | FLATENTRYLIST

CbFLATENTRYLIST (_lplist)

Parameters

_lplist
Pointer to the FLATENTRYLIST structure in question.


CbFLATMTSIDLIST

The CbFLATMTSIDLIST macro computes the number of bytes in an existing FLATMTSIDLIST structure.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | FLATMTSIDLIST

CbFLATMTSIDLIST (_lplist)

Parameters

_lplist
Pointer to the existing FLATMTSIDLIST structure.


CbMAPIFormInfoArray

The CbMAPIFormInfoArray macro computes the number of bytes in an existing SMAPIFormInfoArray structure containing a specified number of form information objects.

Quick Info

Header file: | MAPIFORM.H
Related structure: | SMAPIFormInfoArray

CbMAPIFormInfoArray (_c)

Parameters

_c
Count of form information objects in the existing SMAPIFormInfoArray structure.


CbMAPIFormPropArray

The CbMAPIFormPropArray macro computes the number of bytes in an existing SMAPIFormPropArray structure containing a specified number of SMAPIFormProp structures.

Quick Info

Header file: | MAPIFORM.H
Related structure: | SMAPIFormPropArray

CbMAPIFormPropArray (_c)

Parameters

_c
Count of SMAPIFormProp structures in the SMAPIFormPropArray structure in question.


CbMAPIVerbArray

The CbMAPIVerbArray macro computes the number of bytes in an existing SMAPIVerbArray structure containing a specified number of SMAPIVerb structures.

Quick Info

Header file: | MAPIFORM.H
Related structure: | SMAPIVerbArray

int CbMAPIVerbArray (_c)

Parameters

_c
Count of SMAPIVerb structures in the existing SMAPIVerbArray structure.


CbMessageClassArray

The CbMessageClassArray macro computes the number of bytes in an existing SMessageClassArray structure containing a specified number of string pointers to message classes.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SMessageClassArray

CbMessageClassArray (_c)

Parameters

_c
Count of the pointers to message classes that are included in the existing SMessageClassArray.


CbMTSID

The CbMTSID macro computes the number of bytes in an existing MTSID structure.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | MTSID

CbMTSID (_lpentry)

Parameters

_lpentry
Pointer to the existing MTSID structure.


CbNewADRLIST

The CbNewADRLIST macro computes the number of bytes that should be allocated for a new ADRLIST structure containing a specified number of recipients represented by ADRENTRY structures.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | ADRLIST

CbNewADRLIST (_centries)

Parameters

_centries
Count of ADRENTRY structures to be included in the new ADRLIST structure.


CbNewENTRYID

The CbNewENTRYID macro computes the number of bytes that should be allocated for a new ENTRYID structure of a specified size.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | ENTRYID

CbNewENTRYID (_cb)

Parameters

_cb
Count of bytes in the entry identifier to be stored in the new ENTRYID structure.


CbNewFLATENTRY

The CbNewFLATENTRY macro computes the number of bytes that should be allocated for a new FLATENTRY structure containing an entry identifier of a specified byte size.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | FLATENTRY

CbNewFLATENTRY (_cb)

Parameters

_cb
Count of bytes in the entry identifier to be included in the new FLATENTRY structure.


CbNewFLATENTRYLIST

The CbNewFLATENTRYLIST macro computes the number of bytes that should be allocated for a new FLATENTRYLIST structure containing a number of FLATENTRY structures of a specified size.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | FLATENTRYLIST

CbNewFLATENTRY (_cb)

Parameters

_cb
Count of bytes in the FLATENTRY structures to be included in the new FLATENTRYLIST structure.


CbNewFLATMTSIDLIST

The CbNewFLATMTSIDLIST macro computes the number of bytes that should be allocated for a new FLATMTSIDLIST structure containing a number of MTSID structures of a specified size.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | FLATMTSIDLIST

CbNewFLATMTSIDIDLIST (_cb)

Parameters

_cb
Count of bytes in the MTSID structures to be included in the new FLATMTSIDLIST structure.


CbNewMTSID

The CbNewMTSID macro computes the number of bytes that should be allocated for a new MTSID structure with a message transfer agent identifier of a specified size.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | MTSID

CbNewMTSID (_cb)

Parameters

_cb
Count of bytes for the message transfer agent identifier to be included in the new MTSID structure.


CbNewSPropAttrArray

The CbNewSPropAttrArray macro computes the number of bytes that should be allocated for a new SPropAttrArray structure containing a specified number of property attributes.

Quick Info

Header file: | IMESSAGE.H
Related structure: | SPropAttrArray

CbNewSPropAttrArray (_cattr)

Parameters

_cattr
Count of property attributes to be included in the new SPropAttrArray structure.


CbNewSPropProblemArray

The CbNewSPropProblemArray macro computes the number of bytes to be allocated for a new SPropProblemArray structure containing a specified number of SPropProblem structures.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SPropProblemArray

CbNewSPropProblemArray (_cprob)

Parameters

_cprob
Count of SPropProblem structures to be included in the new SPropProblemArray structure.


CbNewSPropTagArray

The CbNewSPropTagArray macro computes the number of bytes to be allocated for a new SPropTagArray structure containing a specified number of property tags.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SPropTagArray

CbNewSPropTagArray (_ctag)

Parameters

_ctag
Count of property tags to be included in the new SPropTagArray structure.


CbNewSRowSet

The CbNewSRowSet macro computes the number of bytes to be allocated for a new SRowSet structure containing a specified number of rows represented by SRow structures.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SRowSet

CbNewSRowSet (_crow)

Parameters

_crow
Count of SRow structures indicating the number of rows to be included in the new SRowSet structure.


CbNewSSortOrderSet

The CbNewSSortOrderSet macro computes the number of bytes to be allocated for a new SSortOrderSet structure containing a specified number of sort orders represented by SSortOrder structures.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SSortOrderSet

CbNewSSortOrderSet (_csort)

Parameters

_csort
Count of SSortOrder structures to be included in the SSortOrderSet structure.


CbSPropAttrArray

The CbSPropAttrArray macro computes the number of bytes in an existing SPropAttrArray structure.

Quick Info

Header file: | IMESSAGE.H
Related structure: | SPropAttrArray

CbSPropAttrArray (_lparray)

Parameters

_lparray
Pointer to the existing SPropAttrArray structure.


CbSPropProblemArray

The CbSPropProblemArray macro computes the number of bytes in an existing SPropProblemArray structure.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SPropProblemArray

CbSPropProblemArray (_lparray)

Parameters

_lparray
Pointer to the existing SPropProblemArray structure.


CbSPropTagArray

The CbSPropTagArray macro computes the number of bytes in an existing SPropTagArray structure.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SPropTagArray

CbSPropTagArray (_lparray)

Parameters

_lparray
Pointer to the existing SPropTagArray structure.


CbSRowSet

The CbSRowSet macro computes the number of bytes in an existing SRowSet structure.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SRowSet

CbSRowSet (_lprowset)

Parameters

_lprowset
Pointer to the existing SRowSet structure.


CbSSortOrderSet

The CbSSortOrderSet macro computes the number of bytes in an existing SSortOrderSet structure.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SSortOrderSet

CbSSortOrderSet (_lpset)

Parameters

_lpset
Pointer to the existing SSortOrderSet structure.


CHANGE_PROP_TYPE

The CHANGE_PROP_TYPE macro updates the property type of a property tag to a specified value. The property identifier is unchanged.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SPropValue

CHANGE_PROP_TYPE (ulPropTag, ulPropType)

Parameters

ulPropTag
The property tag to be modified.
ulPropType
The new value for the property type.


IsEqualMAPIUID

The IsEqualMAPIUID macro tests two MAPIUID structures to determine if they contain the same identifier.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | MAPIUID

IsEqualMAPIUID(lpuid1, lpuid2)

Parameters

lpuid1
Pointer to the first MAPIUID structure to be tested.
lpuid2
Pointer to the second MAPIUID structure to be tested.

Remarks

The IsEqualMAPIUID macro returns TRUE if the two MAPIUID structures contain the same identifier and FALSE if they do not.

The IsEqualMAPIUID macro requires that the header file MEMORY.H be included.


MVI_PROP

The MVI_PROP macro sets the MVI_FLAG for a specified property.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SPropValue

MVI_PROP (tag)

Parameters

tag
The property tag to be modified.

Remarks

The MVI_FLAG combines the setting of MV_FLAG, identifying a property as multivalued, and MV_INSTANCE, requesting that a multivalued property be displayed in a table in multiple rows. The property type of the affected property is modified, but the identifier remains unchanged.

For example, when the MVI_PROP macro is applied to a property of type PT_FLOAT, its type is changed to PT_MV_FLOAT. When included in a table, multiple rows are used to represent the property with one row for each value. The properties for the other columns are repeated.

For more information about these flags, see About Property Types and Working with Multivalued Columns.


PROP_ID

The PROP_ID macro returns the property identifier of a specified property tag.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SPropValue

PROP_ID (ulPropTag)

Parameters

ulPropTag
Property tag containing the identifier to be returned.

Remarks

Every property tag contains the property type in the low-order word (bits 0 through 15) and the property identifier in the high-order word (bits 16 through 31). The PROP_ID macro extracts the property identifier and places it in bits 0 through 15 of the integer to be returned. The remaining bits of the return value are set to zeros.

The PROP_ID macro can be used, for example, to retrieve an identifier to pass to IMAPIProp::GetNamesFromIDs. GetNamesFromIDs retrieves the property name associated with an identifier for a named property.


PROP_TAG

The PROP_TAG macro returns a property tag created by combining a specified property type and identifier.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SPropValue

PROP_TAG (ulPropType, ulPropID)

Parameters

ulPropType
Property type for the new property tag.
ulPropID
Property identifier for the new property tag.

Remarks

The PROP_TAG macro creates a property tag for a property of type ulPropType and the identifier that is specified in ulPropID. For example, a property tag for an entry identifier can be created with the PROP_TAG macro as follows:

PROP_TAG( PT_BINARY, 0x0FFF)

The low-order 16 bits of the returned property tag contain the property type, PT_BINARY, and the high-order 16 bits contain the property identifier, 0xFFFF.

For more information about property tags, see About Property Tags.


PROP_TYPE

The PROP_TYPE macro returns the property type of a specified property tag.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SPropValue

PROP_TYPE (ulPropTag)

Parameters

ulPropTag
Property tag containing the property type to be returned.

Remarks

The PROP_TYPE macro can be used to determine the type of a property. For example, calling PROP_TYPE(PR_ENTRYID) results in the value PT_BINARY being returned.

Every property tag contains the property type in the low-order word (bits 0 through 15) and the property identifier in the high-order word (bits 16 through 31). The PROP_TYPE macro extracts the property type and places it in bits 0 through 15 of the integer to be returned. The remaining bits of the return value are set to zeros.


SizedADRLIST

The SizedADRLIST macro defines an ADRLIST structure with the specified name containing a specified number of ADRENTRY structures.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | ADRLIST

SizedADRLIST (_centries, _name)

Parameters

_centries
Count of ADRENTRY structures to be included in the new ADRLIST structure.
_name
Name for the new ADRLIST structure.

Remarks

The SizedADRLIST macro provides a way to define a recipient list with explicit bounds when array length requirements are known. The following code shows how to cast the result of the SizedADRLIST macro to an ADRLIST structure pointer:

lpADRList = (LPADRLIST) &SizedADRList;


SizedDtblButton

The SizedDtblButton macro creates a named structure that includes a DTBLBUTTON structure for describing a button and a label of a specified length.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | DTBLBUTTON

SizedDtblButton (n, u)

Parameters

n
Length of the label to be included in the new structure.
u
Name for the new structure.

Remarks

The new structure is created with the following members:

DTBLBUTTON            dtblbutton;
TCHAR                 lpszLabel[n];


SizedDtblCheckBox

The SizedDtblCheckBox macro creates a named structure that includes a DTBLCHECKBOX structure for describing a check box control and a label of a specified length.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | DTBLCHECKBOX

SizedDtblCheckBox (n, u)

Parameters

n
Length of the label to be included in the new structure.
u
Name for the new structure.

Remarks

The SizedDtblCheckBox macro provides a way to define a check box when the number of label characters is known. The new structure is created with the following members:

DTBLCHECKBOX        dtblcheckbox;
TCHAR               lpszLabel[n];

To use a pointer to the resulting structure from the SizedDtblCheckBox macro as a DTBLCHECKBOX structure pointer, perform the following cast:

lpDtblCheckBox = (LPDTBLCHECKBOX) &SizedDtblCheckBox;


SizedDtblComboBox

The SizedDtblComboBox macro creates a named structure that includes a DTBLCOMBOBOX structure for describing a combo box control and the maximum number of characters that can be entered in the associated edit control.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | DTBLCOMBOBOX

SizedDtblComboBox (n, u)

Parameters

n
Number of characters that can be entered in the combo box's edit control.
u
Name for the new structure.

Remarks

The SizedDtblComboBox macro provides a way to define a combo box when the length of the allowed character string is known. The new structure is created with the following members:

DTBLCOMBOBOX        dtblcombobox;
TCHAR               lpszCharsAllowed[n];

To use a pointer to the resulting structure from the SizedDtblComboBox macro as a DTBLCOMBOBOX structure pointer, perform the following cast:

lpDtblComboBox = (LPDTBLCOMBOBOX) &SizedDtblComboBox;


SizedDtblEdit

The SizedDtblEdit macro creates a named structure that includes a DTBLEDIT structure for describing an edit control and the maximum number of characters that can be entered in the control.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | DTBLEDIT

SizedDtblEdit (n, u)

Parameters

n
Maximum number of characters that can be entered in the edit control.
u
Name for the new structure.

Remarks

The SizedDtblEdit macro provides a way to define an edit control when the number of allowed characters is known. The new structure is created with the following members:

DTBLEDIT                dtbledit;
TCHAR                   lpszCharsAllowed[n];

To use a pointer to the resulting structure from the SizedDtblEdit macro as a DTBLEDIT structure pointer, perform the following cast:

lpDtblEdit = (LPDTBLEDIT) &SizedDtblEdit;


SizedDtblGroupBox

The SizedDtblGroupBox macro creates a named structure that includes a DTBLGROUPBOX structure for describing a group box control and a label of a specified length.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | DTBLGROUPBOX

SizedDtblGroupBox (n, u)

Parameters

n
Length of the group box's label.
u
Name for the new structure.

Remarks

The SizedDtblGroupBox macro provides a way to define a group box control when the length of the label is known. The new structure is created with the following members:

DTBLGROUPBOX            dtblgroupbox;
TCHAR                   lpszLabel[n];

To use a pointer to the resulting structure from the SizedDtblGroupBox macro as a DTBLGROUPBOX structure pointer, perform the following cast:

lpDtblGroupBox = (LPDTBLGROUPBOX) &SizedDtblGroupBox;


SizedDtblLabel

The SizedDtblLabel macro creates a named structure that includes a DTBLLABEL structure for describing a label control and the associated label of a specified length.

Quick Info

Specified in header file: | MAPIDEFS.H
Related structure | DTBLLABEL

SizedDtblLabel (n, u)

Parameters

n
Length of the label, including the terminating NULL character.
u
Name for the new structure.

Remarks

The SizedDtblLabel macro provides a way to define a display table label when the number of characters in the label is known. The new structure is created with the following members:

DTBLLABEL            dtbllabel;
TCHAR                lpszLabelName[n];

To use a pointer to the resulting structure from the SizedDtblLabel macro as a DTBLLABEL structure pointer, perform the following cast:

lpDtblLabel = (LPDTBLLABEL) &SizedDtblLabel;


SizedDtblPage

The SizedDtblPage macro creates a named structure that includes a DTBLPAGE structure for describing a tabbed page control, a label of a specified length, and a Help file entry of a specified length.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | DTBLPAGE

SizedDtblPage (n, n1, u)

Parameters

n
Length of the label for the page tab.
n1
Length of the entry appearing in the MAPISVC.INF file identifying the Help file to be used with the tabbed page control.
u
Name for the new structure.

Remarks

The SizedDtblPage macro provides a way to define a tabbed page control when the number of characters in the associated label and Help file entry is known. The new structure is created with the following members:

DTBLPAGE                dtblpage;
TCHAR                   lpszLabel[n];
TCHAR                   lpszComponent[n1];

To use a pointer to the resulting structure from the SizedDtblPage macro as a DTBLPAGE structure pointer, perform the following cast:

lpDtblPage = (LPDTBLPAGE) &SizedDtblPage;


SizedENTRYID

The SizedENTRYID macro creates a named ENTRYID structure that contains an ab member of a specified size.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | ENTRYID

SizedENTRYID (_cb, _name)

Parameters

_cb
Count of bytes in the ab member of the new structure.
_name
Name for the new structure.

Remarks

The SizedENTRYID macro provides a way to define an entry identifier after array length requirements are known. Use this macro to create an entry identifier with explicit bounds.

To use the new structure that results from the SizedENTRYID macro as a pointer to an ENTRYID structure, perform the following cast:

lpENTRYID = (LPENTRYID) &SizedENTRYID;


SizedSPropProblemArray

The SizedSPropProblemArray macro creates a named SPropProblemArray structure that contains a specified number of SPropProblem structures.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SPropProblemArray

SizedSPropProblemArray (_cprob, _name)

Parameters

_cprob
Count of SPropProblem structures to be included in the new structure.
_name
Name for the new structure.

Remarks

Use the SizedSPropProblemArray macro to create a property problem array with explicit bounds. To use the new structure that results from the SizedSPropProblemArray macro as a pointer to an SPropProblemArray structure, perform the following cast:

lpPropProbArray = (LPSPropProblemArray) &SizedSPropProblemArray;


SizedSPropTagArray

The SizedSPropTagArray macro creates a named SPropTagArray structure that includes a specified number of property tags.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SPropTagArray

SizedSPropTagArray (_ctag, _name)

Parameters

_ctag
Count of property tags to be included in the new structure.
_name
Name for the new structure.

Remarks

Use the SizedSPropTagArray macro to create a property tag array with explicit bounds.

To use the new structure that results from the SizedSPropTagArray macro as a pointer to an SPropTagArray structure, perform the following cast:

lpPropTagArray = (LPPropTagArray) &SizedSPropTagArray;


SizedSRowSet

The SizedSRowSet macro creates a named SRowSet structure that contains a specified number of rows.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SRowSet

SizedSRowSet (_crow, _name)

Parameters

_crow
Count of the number of rows to be included in the new structure.
_name
Name for the new structure.

Remarks

To use the new structure that results from the SizedSRowSet macro as a pointer to an SRowSet structure, perform the following cast:

lpSRowSet = (LPSRowSet) &SizedSRowSet;


SizedSSortOrderSet

The SizedSSortOrderSet macro creates a named SSortOrderSet structure that contains a specified number of sort orders.

Quick Info

Header file: | MAPIDEFS.H
Related structure: | SSortOrderSet

SizedSSortOrderSet (_csort, _name)

Parameters

_csort
Count of sort orders to be included in the new structure.
_name
Name for the new structure.

Remarks

Use the SizedSSortOrderSet macro to create a sort order set with explicit bounds.

To use the new structure that results from the SizedSSortOrderSet macro as a pointer to an SSortOrderSet structure, perform the following cast:

lpSSortOrderSet = (LPSSortOrderSet) &SizedSSortOrderSet;


MAPI Data Types

The following alphabetized entries contain documentation for the data types used in MAPI methods, functions, and structures.


BOOKMARK

The BOOKMARK data type is an unsigned long integer that is used to define bookmarks — data for remembering a position in a table.

Quick Info

Header file: MAPIDEFS.H
Related methods: IMAPITable::CreateBookmark
IMAPITable::FreeBookmark

typedef ULONG BOOKMARK;

Remarks

MAPI defines three bookmarks, listed as follows:

BOOKMARK_BEGINNING
Remembers the beginning position of the table.
BOOKMARK_CURRENT
Remembers the current position of the table.
BOOKMARK_END
Remembers the ending position of the table.

Clients can create other bookmarks for remembering other table positions. Bookmarks are valid only while the table is open. Clients must free any bookmarks that they have created before closing the associated table.

See Also

IMAPITable::CreateBookmark, IMAPITable::FindRow, IMAPITable::FreeBookmark, IMAPITable::SeekRow


HRESULT

The HRESULT data type is a 32-bit value that is used to describe an error or warning.

typedef LONG          HRESULT;

Remarks

On 32-bit platforms, the HRESULT data type is the same as the SCODE data type. On 16-bit platforms, an SCODE value is used to generate an HRESULT value.

An HRESULT value is made up of the following fields:

  • A 1-bit code indicating severity, where zero represents success and 1 represents failure.
  • A 4-bit reserved value.
  • An 11-bit code indicating responsibility for the error or warning, also known as a facility code.
  • A 16-bit code describing the error or warning.

Most MAPI interface methods and functions return HRESULT values to provide detailed result information. HRESULT values are also used widely in OLE interface methods. OLE provides several macros for converting between HRESULT values and SCODE values, another common data type for error handling. For information about the OLE use of HRESULT values, see the OLE Programmer's Reference. For more information about the use of these values in MAPI, see Error Handling and any of the following interface methods:

IABLogon::GetLastError

IMAPISupport::GetLastError

IMAPIControl::GetLastError

IMAPITable::GetLastError

IMAPIProp::GetLastError

IMAPIViewAdviseSink::OnPrint

See Also

SCODE


LHANDLE

The LHANDLE data type is an unsigned long integer that is used in Simple MAPI as a session handle.

Quick Info

Header file: MAPI.H

typedef unsigned long LHANDLE, FAR *LPLHANDLE;


SCODE

The SCODE data type is a 32-bit status value that is used to describe an error or warning.

typedef ULONG     SCODE;

Remarks

On 32-bit platforms, the SCODE data type is the same as the HRESULT data type. On 16-bit platforms, an SCODE value is used to generate an HRESULT value.

An SCODE value is divided into four fields:

  • A single-bit severity code which is set to 0 to indicate success and 1 to indicate failure.
  • An 11-bit reserved field
  • A 4-bit facility code which indicates the area responsible for the error or warning.
  • A 16-bit error or warning code which describes the problem causing the error or warning.

Many of the MAPI functions and methods return SCODE values defined as HRESULT data types as do the OLE methods and functions. OLE defines several macros that can be used to convert between an SCODE and an HRESULT on a 16-bit platform.

For more information about how MAPI uses the SCODE data type, see Error Handling. For more information about OLE and the SCODE data type, see the OLE Programmer's Reference.

See Also

HRESULT


TCHAR

The TCHAR data type is a Win32 character string that can be used to describe ANSI, DBCS, or Unicode strings. For ANSI and DBCS platforms, TCHAR is defined as follows:

typedef char          TCHAR;

For Unicode platforms, TCHAR is defined as synonymous with the WCHAR type.

Remarks

MAPI clients can use the TCHAR data type to represent a string of either the WCHAR or char type. Be sure to define the symbolic constant UNICODE and limit the platform where necessary. MAPI will interpret the platform information and internally translate TCHAR to the appropriate string. The MAPI property type, PT_TSTRING, works the same way as the TCHAR data type. When the platform supports Unicode, properties of type PT_TSTRING are assigned the type PT_UNICODE at compile time. When the platform does not support Unicode, these properties are assigned the type PT_STRING8.

For more information on this functionality, see Character Sets and List of Property Types.


Common Messaging Calls (CMC)

The Common Messaging Calls (CMC) applications programming interface (API) provides a simple and convenient set of functions for applications that need basic messaging functionality. CMC provides for all the major messaging functionality an application should need, such as accessing message stores for sending and receiving messages, and addressing and name resolution services. The functions in the CMC API are typically high level functions and can each be used in several different ways depending on the arguments to the functions. The CMC API makes it possible for the calling application to know nothing about the underlying messaging system or transport mechanism used to implement the CMC API itself.

Most CMC functions use both input and output parameters. Input parameters provide information the CMC implementation uses to perform the tasks needed by the calling application. The CMC implementation uses output parameters to pass information back to the calling application from a CMC function. Some functions have parameters used for both input and output.

Data structures and symbolic constants for CMC and its extensions are described in this reference. Their C language definitions can be found in the following header files:

Header file name | Header file contents
XCMC.H | CMC data structures and symbolic constants.
XCMCEXT.H | Common CMC extension data structures and symbolic constants.
XCMCMSXT.H | Microsoft CMC extension data structures and symbolic constants.


Functions

The following functions are implemented in compliance with the X.400 API Association's Common Messaging Call API specification. These functions make heavy use of extensions, which are described in the Data Extensions section of the CMC reference. The functions are listed in alphabetical order.


cmc_act_on

The cmc_act_on function performs the specified operation on a message.

Quick Info

Header file: XCMC.H

CMC_return_code cmc_act_on (
  CMC_session_id session,
  CMC_message_reference * message_reference,
  CMC_enum operation,
  CMC_flags act_on_flags,
  CMC_ui_id ui_id,
  CMC_extension FAR * act_on_extensions
)

Parameters

session
[in] Session handle that represents a MAPI session. The value in the session parameter must be a valid session handle, not zero.
message_reference
[in] Pointer to a message reference that identifies the message to be acted upon. A null pointer or a pointer to a message reference of length zero is invalid for any operation requiring a message reference. If the message reference is invalid, the cmc_act_on function returns CMC_E_INVALID_MESSAGE_REFERENCE.
operation
[in] An enumeration variable that identifies the operation to perform on the message. Possible values are:
CMC_ACT_ON_DELETE
Marks the specified message for deletion from the mailbox. This operation requires a valid message_reference parameter.
CMC_ACT_ON_EXTENDED
The operation to be performed is specified in the act_on_extensions parameter.
act_on_flags
[in] Bitmask of option flags. The following flag can be set:
CMC_ERROR_UI_ALLOWED
Displays a dialog box on encountering recoverable errors. If this flag is not set, cmc_act_on does not display a dialog box and returns an error value instead.
ui_id
[in] A handle that cmc_act_on uses to present a dialog box for resolving processing questions.
act_on_extensions
[in, out] Pointer to an array of CMC_extension structures containing function extensions. On input, this array contains MAPI extensions to the standard cmc_act_on function. A value of NULL for the act_on_extensions parameter indicates the caller has no extensions for cmc_act_on and is expecting no extensions. You can use the CMC_X_COM_SAVE_MESSAGE extension to save a message to the receive folder.

On output, cmc_act_on writes to the array new information about its processing. It writes NULL if it generates no output extensions.

Return Values

CMC_E_FAILURE
There was a general failure that does not fit the description of any other return value.
CMC_E_INSUFFICIENT_MEMORY
Insufficient memory was available to complete the requested operation.
CMC_E_INVALID_ENUM
A CMC_enum value was invalid.
CMC_E_INVALID_FLAG
A flag set using a flags parameter was invalid.
CMC_E_INVALID_MESSAGE_REFERENCE
The specified message reference is invalid or no longer valid (for example, it has been deleted).
CMC_E_INVALID_PARAMETER
A function parameter was invalid.
CMC_E_INVALID_SESSION_ID
The specified session handle is invalid or no longer valid — for example, after logging off.
CMC_E_INVALID_UI_ID
The specified user interface identifier is invalid or no longer valid.
CMC_E_MESSAGE_IN_USE
The requested action could not be completed because the message was in use.
CMC_E_UNSUPPORTED_ACTION
The requested action is not supported by the current implementation.
CMC_E_UNSUPPORTED_FLAG
The flag requested is not supported.
CMC_E_UNSUPPORTED_FUNCTION_EXT
The function extension requested is not supported.

See Also

CMC_extension, CMC_X_COM_SAVE_MESSAGE


cmc_free

The cmc_free function frees memory allocated by the message service through another CMC function.

Quick Info

Header file: XCMC.H

CMC_return_code cmc_free (
  CMC_buffer memory
)

Parameters

memory
[in] Pointer to memory previously allocated by CMC. The cmc_free function ignores a parameter value of NULL. After this function completes, the pointer to memory is invalid, and the application cannot reference it again.

Return Values

CMC_E_FAILURE
There was a general failure that does not fit the description of any other return value.
CMC_E_INVALID_MEMORY
A memory pointer passed is invalid.

Remarks

Results of the cmc_free function are unpredictable if the client application calls it with a base pointer to a memory block not allocated by the message service, a base pointer to a memory block already freed, or a nonbase pointer to a complex structure written by another CMC function.

The CMC functions cmc_list, cmc_look_up, cmc_query_configuration, and cmc_read can provide the client application with a base pointer to a complex structure containing several levels of pointers. The client application should free the entire structure or structure array by calling cmc_free with the base pointer.

See Also

cmc_list, cmc_look_up, cmc_query_configuration, cmc_read


cmc_list

The cmc_list function lists summary information for messages that meet client application-specified criteria.

Quick Info

Header file: XCMC.H

CMC_return_code cmc_list (
  CMC_session_id session,
  CMC_string message_type,
  CMC_flags list_flags,
  CMC_message_reference * seed,
  CMC_uint32 FAR * count,
  CMC_ui_id ui_id,
  CMC_message_summary FAR * FAR * result,
  CMC_extension FAR * list_extensions
)

Parameters

session
[in] Opaque session handle that represents a MAPI session object indicating a session with a message service. If the session handle is invalid, this function returns cmc_e_invalid_session_id.
message_type
[in] Pointer to the ASCII name of the type of message for which this function lists information. If the cmc_list function does not recognize the specified message type, it returns cmc_e_unrecognized_message_type. If the function receives a value of NULL for the message type, it lists information for all available message types.
list_flags
[in] Bitmask of flags. The following flags can be set:
CMC_ERROR_UI_ALLOWED
Displays a dialog box on encountering recoverable errors. If this flag is not set, cmc_list does not display a dialog box and returns an error value instead.
CMC_LIST_COUNT_ONLY
Lists only a count of messages meeting the specified criteria, not any actual summary information. If this flag is not set, the function lists summary information in the array.
CMC_LIST_MSG_REFS_ONLY
Writes only message reference information to the array pointed to by the result parameter. If this flag is not set, cmc_list writes information to all members of the structures in the array.
CMC_LIST_UNREAD_ONLY
Lists unread messages only. If this flag is not set, cmc_list can list both read and unread messages.
seed
[in] Pointer to a message reference that identifies the message after which cmc_list should begin to search. A value of NULL for this parameter indicates that the function should start the search with the first message in the mailbox. A pointer to a message reference of length zero is invalid and causes cmc_list to return cmc_e_invalid_message_reference. If the seed parameter is part of a structure that is returned by an earlier CMC call, the structure that was allocated by CMC should be freed before the current session exits.
count
[in, out] A message count. On input, this parameter specifies a pointer to the maximum number of messages for which cmc_list should provide summary information. A value of zero indicates no maximum.

On output, the count parameter specifies the location to which cmc_list writes the number of messages for which it provides summary information. If no messages match the search criteria, or if the mailbox is empty, cmc_list writes zero.

ui_id
[in] Handle of a dialog box for cmc_list to present to help resolve processing questions.
result
[out] Pointer to the location to which cmc_list writes the address of the array of CMC_message_summary structures that it has written.
list_extensions
[in, out] Pointer to an array of CMC_extension structures specifying function extensions. On input, this array contains MAPI extensions to the standard cmc_list function. A value of NULL for the list_extensions parameter indicates that the client application has no extensions for cmc_list and is expecting no extensions.

On output, cmc_list writes to the array new information about its processing of the message summaries. It writes NULL if it generates no output extensions.

Return Values

CMC_E_FAILURE
There was a general failure that does not fit the description of any other return value.
CMC_E_INSUFFICIENT_MEMORY
Insufficient memory was available to complete the requested operation.
CMC_E_INVALID_FLAG
A flag set using a flags parameter was invalid.
CMC_E_INVALID_MESSAGE_REFERENCE
The specified message reference is invalid or no longer valid — for example, it has been deleted.
CMC_E_INVALID_PARAMETER
A function parameter was invalid.
CMC_E_INVALID_SESSION_ID
The specified session handle is invalid or no longer valid — for example, after logging off.
CMC_E_INVALID_UI_ID
The specified user-interface identifier is invalid or no longer valid.
CMC_E_UNRECOGNIZED_MESSAGE_TYPE
The specified message type is not supported by the current implementation.
CMC_E_UNSUPPORTED_FLAG
The flag requested is not supported.
CMC_E_UNSUPPORTED_FUNCTION_EXT
The function extension requested is not supported.

Remarks

The client application can specify a cmc_list search to start with a certain message or to start at the first message in the mailbox. It can also specify the maximum number of messages to list. The cmc_list function writes the summary information for the specified messages in an array of CMC_message_summary structures. Using the message references in these structures, the application can then make calls to the cmc_read and cmc_act_on functions for additional processing.

Before cmc_list writes message summary information, it must allocate memory for the structure array to contain the information. When this memory is no longer needed, the client application should free the entire array with a call to the cmc_free function.

See Also

cmc_act_on, CMC_extension, cmc_free, CMC_message_summary, cmc_read


cmc_logoff

The cmc_logoff function logs a client application off a message service.

Quick Info

Header file: XCMC.H

CMC_return_code cmc_logoff (
  CMC_session_id session,
  CMC_ui_id ui_id,
  CMC_flags logoff_flags,
  CMC_extension FAR * logoff_extensions
)

Parameters

session
[in] Opaque session handle that represents a MAPI session object indicating a session with a message service. If the session handle is invalid, the cmc_logoff function returns cmc_e_invalid_session_id. After cmc_logoff returns, the session handle is invalid.
ui_id
[in] Handle of a dialog box for cmc_logoff to present to help resolve processing questions.
logoff_flags
[in] Bitmask of flags. The following flags can be set:
CMC_ERROR_UI_ALLOWED
Displays a dialog box on encountering recoverable errors. If this flag is not set, cmc_logoff does not display a dialog box and returns an error value instead.
CMC_LOGOFF_UI_ALLOWED
Indicates cmc_logoff can display a dialog box for other purposes than displaying error messages while logging the user off from the session.
logoff_extensions
[in, out] Pointer to an array of CMC_extension structures containing function extensions. On input, this array contains MAPI extensions to the standard cmc_logoff function. A value of NULL for the logoff_extensions parameter indicates that the client application has no extensions for cmc_logoff and is expecting no extensions.

On output, cmc_logoff writes to the array new information about the logoff operation. It writes NULL if it generates no output extensions.

Return Values

CMC_E_FAILURE
There was a general failure that does not fit the description of any other return value.
CMC_E_INSUFFICIENT_MEMORY
Insufficient memory was available to complete the requested operation.
CMC_E_INVALID_FLAG
A flag set using a flags parameter was invalid.
CMC_E_INVALID_PARAMETER
A function parameter was invalid.
CMC_E_INVALID_SESSION_ID
The specified session handle is invalid or no longer valid — for example, after logging off.
CMC_E_INVALID_UI_ID
The specified user-interface identifier is invalid or no longer valid.
CMC_E_UNSUPPORTED_FLAG
The flag requested is not supported.
CMC_E_UNSUPPORTED_FUNCTION_EXT
The function extension requested is not supported.
CMC_E_USER_NOT_LOGGED_ON
The user was not logged on and the CMC_LOGON_UI_ALLOWED flag was not set.

See Also

CMC_extension


cmc_logon

The cmc_logon function logs a client application on to a service provider.

Quick Info

Header file: XCMC.H

CMC_return_code cmc_logon (
  CMC_string service,
  CMC_string user,
  CMC_string password,
  CMC_object_identifier character_set,
  CMC_ui_id ui_id,
  CMC_uint16 caller_CMC_version,
  CMC_flags logon_flags,
  CMC_session_id FAR * session,
  CMC_extension FAR * logon_extensions
)

Parameters

service
[in] Pointer to the location of the service provider for the CMC implementation. Passing NULL for the service parameter indicates either that the client application is requesting logon to a service provider that does not require a service name, or that the client is requesting the CMC implementation's logon dialog box.
user
[in] Pointer to a MAPI profile name identifying the client application. Passing NULL for the user parameter indicates either that the client is requesting logon to a service provider that does not require a user name, or that the client is requesting the CMC implementation's dialog box to prompt for a name.
password
[in] Pointer to a MAPI profile password required for access to the CMC implementation. Passing NULL for the service parameter indicates either that the client is requesting logon to a service provider that does not require a password, or that the client is requesting the CMC implementation's dialog box to prompt for a password.
character_set
[in] Pointer to an object identifier for the character set used by the client application. The client application can call the cmc_query_configuration function to retrieve the available values. The CMC implementation requires a non-null value for the character_set parameter.
ui_id
[in] Handle of a dialog box for the cmc_logon function to present to help resolve processing questions or prompt for logon.
caller_CMC_ version
[in] The client application's CMC version number, multiplied by 100. For example, version 1 is specified as the integer 100.
logon_flags
[in] Bitmask of flags. The following flags can be set:
CMC_COUNTED_STRING_TYPE
The string type the calling application or provider uses for CMC interactions is a CMC_counted_string. If this flag is not set, the function treats all strings as null-terminated strings.
CMC_ERROR_UI_ALLOWED
Displays a dialog box on encountering recoverable errors. If this flag is not set, cmc_logon does not display a dialog box and returns an error value instead.
CMC_LOGON_UI_ALLOWED
Displays a dialog box to prompt for logon if required. If this flag is not set, cmc_logon does not display a dialog box and returns an error value if the user does not supply enough information.
session
[out] Pointer to the location to which cmc_logon writes an opaque session handle. This identifier represents a MAPI session object indicating a session with a message service.
logon_extensions
[in, out] Pointer to an array of CMC_extension structures specifying function extensions. On input, this array contains MAPI extensions to the standard cmc_logon function. A value of NULL for the logon_extensions parameter indicates that the client application has no extensions for cmc_logon and is expecting no extensions.

On output, cmc_logon writes to the array new information about the logon operation. It writes NULL if it generates no output extensions.

Return Values

CMC_E_COUNTED_STRING_UNSUPPORTED
This implementation does not support the counted-string type.
CMC_E_FAILURE
There was a general failure that does not fit the description of any other return value.
CMC_E_INSUFFICIENT_MEMORY
Insufficient memory was available to complete the requested operation.
CMC_E_INVALID_FLAG
A flag set using a flags parameter was invalid.
CMC_E_INVALID_PARAMETER
A function parameter was invalid.
CMC_E_INVALID_UI_ID
The specified user-interface identifier is invalid or no longer valid.
CMC_E_LOGON_FAILURE
The service, user name, or password specified was invalid, so logon cannot be completed.
CMC_E_PASSWORD_REQUIRED
A password is required on this message service.
CMC_E_SERVICE_UNAVAILABLE
The service requested was unavailable.
CMC_E_UNSUPPORTED_CHARACTER_SET
The current implementation does not support the character set requested.
CMC_E_UNSUPPORTED_FLAG
The current implementation does not support the flag requested.
CMC_E_UNSUPPORTED_FUNCTION_EXT
The current implementation does not support the function extension requested.
CMC_E_UNSUPPORTED_VERSION
The current implementation cannot support the version specified in the call.

Remarks

The cmc_logon function can, at the client application's option, either prompt the user for information through a dialog box or proceed without any user interaction. It writes a session handle that the client application can use in subsequent calls to the CMC implementation.

See Also

CMC_extension, cmc_query_configuration


cmc_look_up

The cmc_look_up function looks up addressing information in a directory provided by a specified service provider.

Quick Info

Header file: XCMC.H

CMC_return_code cmc_look_up (
  CMC_session_id session,
  CMC_recipient FAR * recipient_in,
  CMC_flags look_up_flags,
  CMC_ui_id ui_id,
  CMC_uint32 FAR * count,
  CMC_recipient FAR * FAR * recipient_out,
  CMC_extension FAR * look_up_extensions
)

Parameters

session
[in] Opaque session handle that represents a MAPI session object that represents a session with a message service. If the session handle is invalid, the cmc_look_up function returns the cmc_e_invalid_session_id error value.
recipient_in
[in] Pointer to an array of CMC_recipient structures containing recipient data. The cmc_look_up function interprets the array depending on the flags that the client application has set using the look_up_flags parameter. Possible interpretations are as following:
  • If the client application has set one of the flags for name resolution, cmc_look_up obtains the name to resolve from the name member of the first structure in the array. The function checks the corresponding name-type member to discover what resolution should be performed. The cmc_look_up function ignores all recipient structures except the first in the array.
  • If the client application has set the CMC_LOOKUP_DETAILS_UI flag, the information in the array must resolve to only one recipient. If it does not, cmc_look_up returns Cmc_e_ambiguous_recipient. The cmc_look_up function ignores all recipient structures except the first in the array.
  • If the client application has set the CMC_LOOKUP_ADDRESSING_UI flag, cmc_look_up displays the recipients specified in the recipient array in the address-list dialog box.
look_up_flags
[in] Bitmask of flags. The following flags can be set:
CMC_COUNTED_STRING_TYPE
The string type the calling application or provider uses for CMC interactions is a CMC_counted_string. If this flag is not set, the function treats all strings as null-terminated strings.
CMC_ERROR_UI_ALLOWED
Displays a dialog box on encountering recoverable errors. If this flag is not set, cmc_look_up does not display a dialog box and returns an error value instead.
CMC_LOGON_UI_ALLOWED
Displays a dialog box to prompt for logon if required. If this flag is not set, cmc_look_up does not display a dialog box and returns an error value if the user does not supply enough information.
CMC_LOOKUP_ADDRESSING_UI
Displays a dialog box to allow creation of a recipient list for addressing a message and general directory browsing. The recipient list passed to the function is the original recipient list for the dialog box. The function returns the list of recipients created by the user. This flag is optional for implementations to support.
CMC_LOOKUP_DETAILS_UI
Displays a details dialog box for the recipient pointed to in the recipient_in parameter. This dialog box only acts on the first recipient in the list. If the recipient name indicated resolves to more than one address, cmc_look_up does not display the details dialog box and returns cmc_e_ambiguous_recipient.
CMC_LOOKUP_RESOLVE_IDENTITY
Returns a recipient record for the identity of the current user of the message service. If no unique identity can be determined, the implementation carries out ambiguous name resolution to determine the address of the current user.
CMC_LOOKUP_RESOLVE_PREFIX_SEARCH
The search method should be by prefix. In a prefix search, all names matching the prefix string, beginning at the first character of the name, are considered matches. If this flag is not set, the search method should be exact-match. CMC implementations must support simple prefix searching. The availability of wildcard or substring searches is optional.
CMC_LOOKUP_RESOLVE_UI
Attempts to resolve ambiguous names by presenting a name-resolution dialog box to the user. If this flag is not set, resolutions that do not result in a single name return the error value CMC_E_AMBIGUOUS_RECIPIENT for message services that require names to resolve to a single address. Message services that can return multiple addresses can return a list of addresses if the count parameter is non-null. The name_type field in the recipient_out parameter can also be set on input as a hint to aid in resolution of the name. Some CMC implementations might not support this flag. The CMC_LOOKUP_RESOLVE_UI flag is set only when the CMC_LOOKUP_RESOLVE_PREFIX_SEARCH flag is also set.
ui_id
[in] Handle of a dialog box for cmc_look_up to present to help resolve processing questions.
count
[in or out] Contains a maximum name count. On input, this parameter specifies a pointer to the maximum number of names for which cmc_look_up can find addressing information. A value of zero indicates no maximum.

On output, the count parameter specifies the location to which cmc_look_up writes the number of names that it actually writes to the location indicated by the recipient_out parameter. If no names are written, cmc_look_up writes zero to the count parameter.

recipient_out
[out] Pointer to the location to which cmc_look_up writes an array of one or more CMC_recipient structures containing addressing details for the recipients in the array passed in the recipient_in parameter.
look_up_extensions
[in, out] Pointer to an array of CMC_extension structures specifying function extensions. On input, this array contains MAPI extensions to the standard cmc_look_up function. A value of NULL for the look_up_extensions parameter indicates that the client application has no extensions for cmc_look_up and is expecting no extensions.

On output, cmc_look_up writes to the array new information about the lookup operation. It writes NULL if it generates no output extensions.

Return Values

CMC_E_AMBIGUOUS_RECIPIENT
The recipient name was ambiguous. Multiple matches were found.
CMC_E_FAILURE
There was a general failure that does not fit the description of any other return value.
CMC_E_INSUFFICIENT_MEMORY
Insufficient memory was available to complete the requested operation.
CMC_E_INVALID_FLAG
A flag set using a flags parameter was invalid.
CMC_E_INVALID_PARAMETER
A function parameter was invalid.
CMC_E_INVALID_SESSION_ID
The specified session handle is invalid or no longer valid — for example, after logging off.
CMC_E_INVALID_UI_ID
The specified user-interface identifier is invalid or no longer valid.
CMC_E_LOGON_FAILURE
The service, user name, or password specified was invalid, so logon cannot be completed.
CMC_E_NOT_SUPPORTED
The current implementation does not support the operation requested.
CMC_E_RECIPIENT_NOT_FOUND
One or more of the specified recipients were not found.
CMC_E_UNSUPPORTED_DATA_EXT
The current implementation does not support the data extension requested.
CMC_E_UNSUPPORTED_FLAG
The current implementation does not support the flag requested.
CMC_E_UNSUPPORTED_FUNCTION_EXT
The current implementation does not support the function extension requested.
CMC_E_USER_CANCEL
The operation was canceled by the user.
CMC_E_USER_NOT_LOGGED_ON
The user was not logged on and the CMC_LOGON_UI_ALLOWED flag was not set.

Remarks

A client application calls the cmc_look_up function to resolve a display name to a messaging address or to prompt the user to choose among multiple resolved names. A client can also use this function to display a dialog box for creation of recipient lists or to display recipient details.

The cmc_look_up function can write multiple addresses. Before it writes addressing information, it must allocate memory for the structure array to contain the information. When this memory is no longer needed, the client application should free the entire array with a call to cmc_free.

See Also

CMC_extension, cmc_free, CMC_recipient


cmc_query_configuration

The cmc_query_configuration function determines configuration information for the installed CMC implementation.

Quick Info

Header file: XCMC.H

CMC_return_code cmc_query_configuration (
  CMC_session_id session,
  CMC_enum item,
  CMC_buffer reference,
  CMC_extension FAR * config_extensions
)

Parameters

session
[in] Opaque session handle that represents a MAPI session object indicating a session with a message service. If this parameter is set to zero, there is no session and the cmc_query_configuration function returns the default logon information to the buffer indicated by the reference parameter. If the session parameter is set to a nonzero value, cmc_query_configuration returns configuration information as determined by the session. If the value provided for the session parameter is invalid, cmc_query_configuration returns cmc_e_invalid_session_id.
item
[in] Enumerated variable that identifies the configuration information required by the client application. The cmc_query_configuration function will write different values to the buffer or pointer that the reference parameter points to depending on the value of the item parameter. The caller must allocate this buffer or pointer before calling cmc_query_configuration. Possible item values are:
CMC_CONFIG_CHARACTER_SET
The reference parameter should be a pointer to a CMC_object_identifier structure array. The cmc_query_configuration function writes a pointer to the array of CMC_object_identifier structures that indicate the character sets supported by the current CMC implementation to the location pointed at by the reference parameter. The cmc_query_configuration function ends the array with a null CMC_object_identifier structure.

The first object identifier in the array is the default character set used if the calling client application or service provider does not specify one explicitly. The calling client or provider uses one of these object identifiers at logon to specify that the implementation use a different character set than the default. This array should be freed with cmc_free.

CMC_CONFIG_DEFAULT_SERVICE
The reference parameter should be a pointer to a CMC_string data type. The cmc_query_configuration function writes a pointer to the default message service name, if available, to the location indicated by the reference parameter. The cmc_query_configuration function writes NULL to this location if no default service name is available.

The current implementation does not set default message service names, so NULL is always written in response to CMC_CONFIG_DEFAULT_SERVICE.

CMC_CONFIG_DEFAULT_USER
The reference parameter should be a pointer to a CMC_string data type. The cmc_query_configuration function writes a pointer to the default user name, if available, to the location indicated by the reference parameter. The cmc_query_configuration function writes NULL to this location if no default user name is available.

The current implementation does not set default user names, so NULL is always written in response to CMC_CONFIG_DEFAULT_USER.

CMC_CONFIG_LINE_TERM
The reference parameter should be a pointer to a CMC_enum variable, which is set to CMC_LINE_TERM_CRLF if the line delimiter is a carriage return followed by a line feed, CMC_LINE_TERM_LF if the line delimiter is a line feed, or CMC_LINE_TERM_CR if the line delimiter is a carriage return.
CMC_CONFIG_REQ_PASSWORD
The reference parameter should be a pointer to a CMC_enum variable, which is set to CMC_REQUIRED_NO if the password is not required to log on, CMC_REQUIRED_OPT if the password is optional to log on, or CMC_REQUIRED_YES if the password is required to log on.
CMC_CONFIG_REQ_SERVICE
The reference parameter should be a pointer to a CMC_enum variable, which is set to CMC_REQUIRED_NO if the service name is not required to log on, CMC_REQUIRED_OPT if the service name is optional to log on, or CMC_REQUIRED_YES if the service name is required to log on.
CMC_CONFIG_REQ_USER
The reference parameter should be a pointer to a CMC_enum variable, which is set to CMC_REQUIRED_NO if the user name is not required to log on, CMC_REQUIRED_OPT if the user name is optional to log on, or CMC_REQUIRED_YES if the user name is required to log on.
CMC_CONFIG_SUP_COUNTED_STR
The reference parameter should be a pointer to a CMC_boolean variable, which is set to TRUE if the CMC_COUNTED_STRING_TYPE flag is supported during logon.
CMC_CONFIG_SUP_NOMKMSGREAD
The reference parameter should be a pointer to a CMC_boolean variable, which will be set to TRUE if the cmc_read function supports the CMC_DO_NOT_MARK_AS_READ flag.
CMC_CONFIG_UI_AVAIL
The reference parameter should be a pointer to a CMC_boolean variable, which will be set to TRUE if there is a dialog box provided by the CMC implementation.
CMC_CONFIG_VER_IMPLEM
The reference parameter should be a pointer to a CMC_uint16 variable, which is set to the version number for the implementation, multiplied by 100. For example, version 1.01 returns 101.
CMC_CONFIG_VER_SPEC
The reference parameter should be a pointer to a CMC_uint16 variable, which is set to the CMC specification version number for the implementation, multiplied by 100. For example, version 1.00 returns 100.
reference
[out] Pointer to a buffer or pointer to which cmc_query_configuration writes configuration information. The value of reference depends on the value of item, as previously described.
config_extensions
[in, out] Pointer to an array of CMC_extension structures specifying function extensions. On input, this array contains MAPI extensions to the standard cmc_query_configuration function. A value of NULL for the config_extensions parameter indicates that the client application has no extensions for cmc_query_configuration and is expecting no extensions.

On output, cmc_query_configuration writes to the array new information about the query configuration operation. It writes NULL if it generates no output extensions.

Return Values

CMC_E_FAILURE
There was a general failure that does not fit the description of any other return value.
CMC_E_INSUFFICIENT_MEMORY
Insufficient memory was available to complete the requested operation.
CMC_E_INVALID_ENUM
A CMC_enum value was invalid.
CMC_E_INVALID_PARAMETER
A function parameter was invalid. Either the reference parameter did not point to a writeable location, or the config_extensions parameter was badly formed.
CMC_E_NOT_SUPPORTED
The current implementation does not support the operation requested.
CMC_E_UNSUPPORTED_FUNCTION_EXT
The current implementation does not support the function extension requested.

Remarks

The client application must cast the reference parameter to the CMC_buffer type before calling cmc_query_configuration. The client application must allocate sufficient memory to contain the information passed in the item parameter. When this memory is no longer needed, the client should free this memory with whatever memory management routines it is using, or with a call to the cmc_free function if required by the previous explanation.

See Also

CMC_extension, cmc_free, cmc_read


cmc_read

The cmc_read function reads a specified message.

Quick Info

Header file: XCMC.H

CMC_return_code cmc_read (
  CMC_session_id session,
  CMC_message_reference * message_reference,
  CMC_flags read_flags,
  CMC_message FAR * FAR * message,
  CMC_ui_id ui_id,
  CMC_extension FAR * read_extensions
)

Parameters

session
[in] Opaque session handle that represents a MAPI session object indicating a session with a message service. If the value provided for the session parameter is invalid, the cmc_read function returns cmc_e_invalid_session_id.
message_reference
[in] Pointer to a CMC_message_reference structure containing the message reference of the message to be retrieved. A NULL value for this parameter indicates that cmc_read should retrieve the first message in the mailbox. If the message reference is invalid, cmc_read returns cmc_e_invalid_message_reference.
read_flags
[in] Bitmask of flags. The following flags can be set:
CMC_DO_NOT_MARK_AS_READ
Does not mark messages as read when they are returned. This flag also suppresses sending of receipt reports. The calling client application or service provider can query the implementation to see if it supports this flag by calling the cmc_query_configuration function.
CMC_ERROR_UI_ALLOWED
Displays a dialog box on encountering recoverable errors. If this flag is not set, cmc_read does not display a dialog box and returns an error value instead.
CMC_MSG_AND_ATT_HDRS_ONLY
The attach_filename fields in the CMC_message structure returned in the message parameter will be undefined when cmc_read returns and should be ignored. This flag can be used to reduce the amount of data transferred, because the filenames will not be included in the transfer. If this flag is not set, the attach_filename fields are returned as usual.

Note that if the CMC_MSG_TEXT_NOTE_AS_FILE value is set in the flags of the returned message, the first attachment contains the message text. In this case, cmc_read returns the attach_filename field for that attachment regardless of the setting of the CMC_MSG_AND_ATT_HDRS_ONLY flag.

CMC_READ_FIRST_UNREAD_MESSAGE
Returns the first message that is not marked as read. If this flag is not set, cmc_read should return the first message in the mailbox, whether it is marked as read or not. This flag can only be set when passing a null message reference to receive the first message in the mailbox.
message
[out] Pointer to the location to which cmc_read writes the CMC_message structure containing the message it has read. The function writes attachment data in files, and the CMC_message structure indicates the names of those files in its attachments member. If the client application has set the CMC_MSG_AND_ATT_HDRS_ONLY flag, the function does not indicate any attachment files.
ui_id
[in] Handle of a dialog box for cmc_read to present to help resolve processing questions.
read_extensions
[in, out] Pointer to an array of CMC_extension structures specifying function extensions. On input, this array contains MAPI extensions to the standard cmc_read function. A value of NULL for the read_extensions parameter indicates that the client application has no extensions for cmc_read and is expecting no extensions.

On output, cmc_read writes to the array new information about the read operation. It writes NULL if it generates no output extensions.

Return Values

CMC_E_ATTACHMENT_OPEN_FAILURE
The specified attachment was found but could not be opened, or the attachment file could not be created.
CMC_E_ATTACHMENT_READ_FAILURE
The specified attachment was found and opened, but there was an error reading it.
CMC_E_ATTACHMENT_WRITE_FAILURE
The attachment file was created successfully, but there was an error writing it.
CMC_E_DISK_FULL
Insufficient disk space was available to complete the requested operation — this can refer to local or shared disk space.
CMC_E_FAILURE
There was a general failure that does not fit the description of any other return value.
CMC_E_INSUFFICIENT_MEMORY
Insufficient memory was available to complete the requested operation.
CMC_E_INVALID_FLAG
A flag set using a flags parameter was invalid.
CMC_E_INVALID_MESSAGE_REFERENCE
The specified message reference is invalid or no longer valid — for example, it has been deleted.
CMC_E_INVALID_PARAMETER
A function parameter was invalid.
CMC_E_INVALID_SESSION_ID
The specified session handle is invalid or no longer valid — for example, after logging off.
CMC_E_INVALID_UI_ID
The specified user-interface identifier is invalid or no longer valid.
CMC_E_TOO_MANY_FILES
The current implementation cannot support the number of files specified.
CMC_E_UNABLE_TO_NOT_MARK_READ
The current implementation cannot support the CMC_DO_NOT_MARK_AS_READ flag.
CMC_E_UNSUPPORTED_FLAG
The current implementation does not support the flag requested.
CMC_E_UNSUPPORTED_FUNCTION_EXT
The current implementation does not support the function extension requested.

Remarks

The cmc_read function only reads the first message in the mailbox if the client application passes a null message-reference value.

After processing, cmc_read writes the data from the message into the CMC_message structure. Unless the client application has set the flag CMC_DO_NOT_MARK_AS_READ on input, the message will be marked as read when cmc_read returns. If the client application has set the input flag CMC_MSG_AND_ATT_HDRS_ONLY, cmc_read writes only message and attachment headers on output.

The cmc_read function can write multiple addresses. Before it writes message information, it must allocate memory for the structure to contain that information. When this memory is no longer needed, the client application should free all structures in the array with a call to the cmc_free function.

See Also

CMC_extension, cmc_free, cmc_list, CMC_message, CMC_message_reference, cmc_query_configuration


cmc_send

The cmc_send function sends a message.

Quick Info

Header file: XCMC.H

CMC_return_code cmc_send (
  CMC_session_id session,
  CMC_message FAR * message,
  CMC_flags send_flags,
  CMC_ui_id ui_id,
  CMC_extension FAR s* send_extensions
)

Parameters

session
[in] Opaque session handle that represents a MAPI session object indicating a session with a message service. If the value provided for the session parameter is invalid, the cmc_send function returns cmc_e_invalid_session_id.
message
[in] Pointer to a CMC_message structure identifying the message to be sent. If the client application has not set the flag CMC_SEND_UI_REQUESTED in the send_flags parameter, the message structure must specify at least one primary (TO), carbon-copy (CC), or blind carbon-copy (BCC) recipient. All other structure members are optional. The cmc_send function ignores the time_sent and message_reference members.
send_flags
[in] Bitmask of flags. The following flags can be set:
CMC_COUNTED_STRING_TYPE
The string type the calling application or provider uses for CMC interactions is CMC_counted_string. If this flag is not set, the function treats all strings as null-terminated strings.
CMC_ERROR_UI_ALLOWED
Displays a dialog box on encountering recoverable errors. If this flag is not set, cmc_send does not display a dialog box and returns an error value instead.
CMC_LOGON_UI_ALLOWED
Displays a dialog box to prompt for logon if required. If this flag is not set, cmc_send does not display a dialog box and returns an error value if the caller does not supply enough information.
CMC_SEND_UI_REQUESTED
Displays a dialog box to prompt for recipients, message field information, and other sending options. If this flag is not set, cmc_send does not display a dialog box and the caller must specify at least one recipient.
ui_id
[in] Handle of a dialog box for cmc_send to present when resolving processing questions, prompting the user for additional information, or verifying provided information.
send_extensions
[in, out] Pointer to an array of CMC_extension structures specifying function extensions. On input, this array contains MAPI extensions to the standard cmc_send function. A value of NULL for the send_extensions parameter indicates that the client application has no extensions for cmc_send and is expecting no extensions.

On output, cmc_send returns to the array new information about the send operation. It returns NULL if it generates no output extensions.

Return Values

CMC_E_AMBIGUOUS_RECIPIENT
The recipient name was ambiguous. Multiple matches were found.
CMC_E_ATTACHMENT_NOT_FOUND
The specified attachment was not found as specified.
CMC_E_ATTACHMENT_OPEN_FAILURE
The specified attachment was found but could not be opened, or the attachment file could not be created.
CMC_E_ATTACHMENT_READ_FAILURE
The specified attachment was found and opened, but there was an error reading it.
CMC_E_ATTACHMENT_WRITE_FAILURE
The attachment file was created successfully, but there was an error writing it.
CMC_E_COUNTED_STRING_UNSUPPORTED
The current implementation does not support the counted-string type.
CMC_E_FAILURE
There was a general failure that does not fit the description of any other return value.
CMC_E_INSUFFICIENT_MEMORY
Insufficient memory was available to complete the requested operation.
CMC_E_INVALID_FLAG
A flag set using a flags parameter was invalid.
CMC_E_INVALID_MESSAGE_PARAMETER
One of the parameters in the message was invalid.
CMC_E_INVALID_PARAMETER
A function parameter was invalid.
CMC_E_INVALID_SESSION_ID
The specified session handle is invalid or no longer valid — for example, after logging off.
CMC_E_INVALID_UI_ID
The specified user-interface identifier is invalid or no longer valid.
CMC_E_LOGON_FAILURE
The service, user name, or password specified were invalid, so logon cannot be completed.
CMC_E_RECIPIENT_NOT_FOUND
One or more of the specified recipients were not found.
CMC_E_TEXT_TOO_LARGE
The size of the text string passed to the current implementation is too large.
CMC_E_TOO_MANY_FILES
The current implementation cannot support the number of files specified.
CMC_E_TOO_MANY_RECIPIENTS
The current implementation cannot support the number of recipients specified.
CMC_E_UNSUPPORTED_DATA_EXT
The current implementation does not support the data extension requested.
CMC_E_UNSUPPORTED_FLAG
The current implementation does not support the flag requested.
CMC_E_UNSUPPORTED_FUNCTION_EXT
The current implementation does not support the function extension requested.
CMC_E_USER_CANCEL
The operation was canceled by the user.
CMC_E_USER_NOT_LOGGED_ON
The user was not logged on and the CMC_LOGON_UI_ALLOWED flag was not set.

Remarks

The cmc_send function can, at the client application's option, either use an interface, like a dialog box, to prompt the user for message creation or proceed without any user interaction. A successful return from this function does not necessarily imply recipient validation.

The client application can optionally provide recipient list, subject text, attachments, and note text for the message. If the client application does not provide the required message elements, the cmc_send function can prompt the user for them if a dialog box is available. If the client provides one or more recipients, the function can send the message without prompting the user. If the client provides optional parameters and requests a dialog box, the parameters provide the initial values for the dialog box.

The following conditions apply to the CMC_message structure members:

message_type
To specify an interpersonal message, use a pointer to the string "CMC:IPM". If the client application provides a pointer value of NULL or a pointer to an empty string, cmc_send uses the default string CMC:IPM.
subject
A pointer value of NULL indicates no subject text.
text_note
A pointer value of NULL indicates no message text. If the client application does pass a non-null value to indicate the message text that exceeds the limits of the service provider, the provider can demote the text to an attachment. Alternatively, it can cause cmc_send to return cmc_e_text_too_large.
recipients
A pointer value of NULL indicates no recipients. If the client application passes a non-null value to indicate recipients in excess of the number of recipients that the service provider allows per message, cmc_send returns cmc_e_too_many_recipients.

Note that the CMC_recipient structure pointed to by recipients can include either the recipient's name, an address, or a name and address pair. If the client application specifies only a name, cmc_send resolves the name to an address using name resolution rules defined by the CMC implementation. If the client specifies only an address, cmc_send uses this address for delivery and for the recipient display name. Finally, if the client specifies a name and address pair, cmc_send does not resolve the name.

The cmc_send function does not require a recipient of type originator to send a message.

attachments
A pointer value of NULL indicates no attachments. If the client application passes a non-null value to indicate attachments in excess of the number of attachments that the service provider allows per message, cmc_send returns cmc_e_too_many_files.

The cmc_send function reads the attachment files before it returns. Thus the caller or user can freely change or delete attachment files after cmc_send returns without affecting the message.

message_flags
Bitmask of message flags. The following flag can be set:
CMC_MSG_TEXT_NOTE_AS_FILE
The text_note member of the message parameter is ignored and the message text is contained in the file referred to by the first attachment. If this flag is set to zero, the message text is contained in the text_note member.

See Also

CMC_extension, CMC_message, CMC_recipient


cmc_send_documents

The cmc_send_documents function sends a document.

Quick Info

Header file: XCMC.H

CMC_return_code cmc_send_documents (
  CMC_string recipient_addresses,
  CMC_string subject,
  CMC_string text_note,
  CMC_flags send_doc_flags,
  CMC_string file_paths,
  CMC_string file_names,
  CMC_string delimiter,
  CMC_ui_id ui_id
)

Parameters

recipient_addresses
[in] Pointer to the address of the document recipient. When the client application specifies multiple recipients, it should separate the strings using the character specified by the delimiter parameter. The cmc_send_documents function assumes a recipient to be a primary recipient unless the address is prefixed by CC: (carbon copy) or BCC: (blind carbon copy). The TO: prefix can optionally be used with the primary recipient for consistency with the other recipient types. Passing NULL in the recipient_addresses parameter indicates that cmc_send_documents should present a dialog box to prompt for recipients.
subject
[in] Pointer to the subject of the document. Passing NULL in the subject parameter indicates no subject text.
text_note
[in] Pointer to the text note carried with the document. Passing NULL in the text_note parameter indicates no text note.
send_doc_flags
[in] Bitmask of flags used to control how documents are sent. The following flags can be set:
CMC_COUNTED_STRING_TYPE
The string type the calling application or provider uses for CMC interactions is CMC_counted_string. If this flag is not set, the function treats all strings as null-terminated strings.
CMC_ERROR_UI_ALLOWED
Displays a dialog box on encountering recoverable errors. If this flag is not set, cmc_send_documents does not display a dialog box and returns an error value instead.
CMC_FIRST_ATTACH_AS_TEXT_NOTE
Sends the first attachment as the message text. If this flag is not set, the text_note field contains the text note.
CMC_LOGON_UI_ALLOWED
Displays a dialog box to prompt for logon if required. If this flag is not set, cmc_send_documents does not display a dialog box and returns an error if the user does not supply enough information.
CMC_SEND_UI_REQUESTED
Displays a dialog box to prompt for recipients, message field information, and other sending options. If this flag is not set, cmc_send_documents does not display a dialog box but must specify at least one recipient.
file_paths
[in] Pointer to the actual path for the attachment file. When the client application specifies multiple paths, it should separate the names using the character indicated by the delimiter parameter.
attach_titles
[in] Pointer to the title of the attachment displayed for the recipient. When the client application specifies multiple titles, it should separate the titles using the character indicated by the delimiter parameter.
delimiter
[in] Pointer to a character used to delimit the names in the file_paths, attach_titles, and recipient_addresses strings. The client application should choose a character that is not used in operating system filenames or recipient names. This parameter cannot be NULL.
ui_id
[in] Handle of a dialog box for cmc_send_documents to present to help resolve processing questions or prompt the user for additional information as required.

Return Values

CMC_E_ATTACHMENT_NOT_FOUND
The specified attachment was not found as specified.
CMC_E_ATTACHMENT_OPEN_FAILURE
The specified attachment was found but could not be opened, or the attachment file could not be created.
CMC_E_ATTACHMENT_READ_FAILURE
The specified attachment was found and opened, but there was an error reading it.
CMC_E_ATTACHMENT_WRITE_FAILURE
The attachment file was created successfully, but there was an error writing it.
CMC_E_COUNTED_STRING_NOT_SUPPORTED
The current implementation does not support counted strings.
CMC_E_FAILURE
There was a general failure that does not fit the description of any other return value.
CMC_E_INSUFFICIENT_MEMORY
Insufficient memory was available to complete the requested operation.
CMC_E_INVALID_FLAG
A flag set using a flags parameter was invalid.
CMC_E_INVALID_PARAMETER
A function parameter was invalid.
CMC_E_INVALID_UI_ID
The specified user-interface identifier is invalid or no longer valid.
CMC_E_LOGON_FAILURE
The service, user name, or password specified was invalid, so logon cannot be completed.
CMC_E_RECIPIENT_NOT_FOUND
One or more of the specified recipients were not found.
CMC_E_TEXT_TOO_LARGE
The size of the text string passed to the current implementation is too large.
CMC_E_TOO_MANY_FILES
The current implementation cannot support the number of files specified.
CMC_E_TOO_MANY_RECIPIENTS
The current implementation cannot support the number of recipients specified.
CMC_E_UNSUPPORTED_FLAG
The current implementation does not support the flag requested.
CMC_E_USER_CANCEL
The operation was canceled by the user.
CMC_E_USER_NOT_LOGGED_ON
The user was not logged on and the CMC_LOGON_UI_ALLOWED flag was not set.

Remarks

The cmc_send_documents function is primarily useful for calls from a scripting language application, such as a spreadsheet application using macros, that cannot handle data structures. The cmc_send_documents function tries to establish a session without a logon dialog box. If this is not possible, it prompts the user for logon information to establish a session. Before the function returns, it closes the session.


Structures and Data Types

The following data structures and simple data types are used by the CMC implementation to pass information in to and out of CMC functions. Wherever possible, you should use these types to maintain compatibility with different CMC implementations.The structures and data types are listed in alphabetical order.


BYTE

BYTE is an unsigned character data type that is binary data.

Quick Info

Header file: WINDEF.H

typedef unsigned char     BYTE;


CMC_attachment

A CMC_attachment structure contains a CMC message attachment.

Quick Info

Header file: XCMC.H

typedef struct
{
     CMC_string     attach_title;
     CMC_object_identifier attach_type;
     CMC_string     attach_filename;
     CMC_flags attach_flags;
     CMC_extension FAR     *attach_extensions;
} CMC_attachment;

Members

attach_title
The optional title for the attachment — for example, the original filename of the attachment.
attach_type
Object identifier that specifies the attachment type. Two attachment types have been defined for use by client applications:
CMC_ATT_OID_BINARY
Data in a file is treated as binary data. This attachment type is the default.
CMC_ATT_OID_TEXT
Data in a file is treated as a text string. This attachment type assumes that data exists in the character set for the session on input and maps to the character set for the session on output, if possible.

A NULL value for attach_type indicates an attachment of an undefined type.

attach_filename
Name of the file in which attachment content is located. The location of the file depends on the CMC implementation, which ensures access by the client application.
attach_flags
Bitmask of flags used to describe attachment options. The following flags can be set:
CMC_ATT_APP_OWNS_FILE
On output, the client application owns the attachment and is responsible for deleting it. This flag is ignored on input. If the flag is not set, it indicates on output that the CMC implementation owns the file and the client application can only read it.
CMC_ATT_LAST_ELEMENT
The last structure in an array of CMC_attachment structures. The structure with this flag set must be at the end of the array. If this flag is set to zero for any structure, that structure is not the last array element.
attach_extensions
Pointer to the first element in an array of CMC_extension structures, each of which is specific to an attachment. Attachment extensions exist to support graphic representation of the attachments in a message when it is displayed. The extensions contain the character positions for the graphic representations. A pointer value of NULL indicates that no extensions are present.

Remarks

A CMC_message structure, which contains information about a CMC message, contains a pointer to an array of one or more CMC_attachment structures defining attachments for the message, or is NULL if there are no attachments. The array elements should have the same order as the attachments in the message, and the last element in the array should have the CMC_ATT_LAST_ELEMENT flag set in its attach_flags member.

See Also

CMC_extension, CMC_message


CMC_boolean

CMC_boolean is a CMC unsigned integer data type that is a Boolean value.

Quick Info

Header file: XCMC.H

typedef      CMC_uint16      CMC_boolean;

Remarks

The CMC_boolean data type can contain the symbolic constants CMC_TRUE and CMC_FALSE. The C interface denotes FALSE by using 0 and TRUE by using any other integer. CMC denotes CMC_FALSE by using 0, in line with C interface usage. However, CMC_TRUE is denoted specifically by the integer 1.


CMC_buffer

CMC_buffer is a CMC data type that points to a memory storage location of an undefined type and size.

Quick Info

Header file: XCMC.H

typedef      void *CMC_buffer;


CMC_counted_string

A CMC_counted_string structure is an optional structure supporting character sets that allow embedded null characters. The structure contains a counted string and explicitly defines the length of the string.

Quick Info

Header file: XCMC.H

typedef struct {
     CMC_uint32     length;
     char      string[1];
} CMC_counted_string;

Members

length
The length, in bytes, of the string specified by the string member.
string
An array of characters that make up the string. CMC does not require the string to be null-terminated.

Remarks

If a client application uses counted strings instead of null-terminated strings, it must set the CMC_COUNTED_STRING_TYPE flag in the cmc_logon function's logon_flags parameter when logging on to a MAPI session through cmc_logon. The data pointed to by a string of type CMC_string is then assumed to be defined as a CMC_counted_string structure.

To determine the character set of a string, the CMC implementation looks at the information for a session identified by a CMC_session_id data type. CMC implementations always attempt to map all strings passed to the client application to the character set for the session. If no session has been created by a call to cmc_logon, CMC interprets the string by using the implementation's default character set.

See Also

CMC_string


CMC_enum

CMC_enum is a CMC data type that is an enumerated data value.

Quick Info

Header file: XCMC.H

typedef      CMC_sint32          CMC_enum;

Remarks

A variable of this type contains a value selected from an enumeration.


CMC_extension

A CMC_extension structure contains a CMC data extension for use by the CMC API functions and data structures. A CMC data extension adds parameters to functions or members to data structures.

Quick Info

Header file: XCMC.H

typedef struct {
     CMC_uint32 item_code;
     CMC_uint32 item_data;
     CMC_buffer item_reference;
     CMC_flags extension_flags;
} CMC_extension;

Members

item_code
Code that uniquely identifies an extension to a function or data structure. The item_code member is the mechanism for specifying the extension to be invoked. The client application puts the extension code in this member before calling CMC functions that use extensions. The possible extensions are:
CMC_X_COM_ATTACH_CHARPOS CMC_X_COM_CAN_SEND_RECIP
CMC_X_COM_CONFIG_DATA CMC_X_COM_PRIORITY
CMC_X_COM_RECIP_ID CMC_X_COM_SAVE_MESSAGE
CMC_X_COM_SENT_MESSAGE CMC_X_COM_SUPPORT_EXT
CMC_X_COM_TIME_RECEIVED CMC_X_MS_ADDRESS_UI
CMC_X_MS_ATTACH_DATA CMC_X_MS_FUNCTION_FLAGS
CMC_X_MS_MESSAGE_DATA CMC_X_MS_SESSION_FLAGS

These extensions are identified by the extension identifiers CMC_XS_COM and CMC_XS_MS. For definitions of these extensions, see Data Extensions.

item_data
Item data for the extension. Depending on the value of item_code, the item_data member might contain the length of the item value, the item value itself, or other information about the item. The specification of the extension describes the interpretation of this member.
item_reference
The item reference for the extension. This value is a pointer to the storage location of the item value. It is NULL if there is no related item storage. The specification of the extension describes the interpretation of this member.
extension_flags
Bitmask of extension flags. The following flags can be set:
CMC_EXT_LAST_ELEMENT
The last structure in an array of CMC_extension structures. The structure with this flag set must be at the end of the array. If this flag is set to zero for any structure, that structure is not the last array element.
CMC_EXT_OUTPUT
For an output extension, the extension structure contains a pointer to implementation-allocated memory that the client application must release with the cmc_free function. If this flag is set to zero, the implementation has not allocated memory for the extension that the application needs to free. This flag is always set to zero for structure extensions.
CMC_EXT_REQUIRED
An error value is returned if this extension cannot be supported. If this flag is set to zero, it enables the CMC implementation to provide any level of support, including no support, for the extension.

Remarks

Extensions are used to add functionality to the CMC API. For example, a client application can implement the cmc_act_on function to allow saving a partially completed message in the receive folder (the Inbox) for later updating and sending. To pass the structure defining this partially completed message to CMC and receive back the resulting message reference, the client application can use the CMC_X_COM_SAVE_MESSAGE extension.

An extension can be either an input extension or an output extension; that is, it can be passed either as input from a client application to CMC or as output from CMC to a client application. Whether the information contained in an extension is input or output is implied by the semantics of the particular extension in question and by the presence or absence of CMC_EXT_OUTPUT in the extension's extension_flags member after a call to a CMC function. For input extensions, the client application in question allocates memory for the extension structure and any other structures associated with the extension. For output extensions, storage for the extension result, if necessary, is allocated by a CMC function.

For output extensions, a client application must free storage allocated by CMC with calls to the cmc_free function. For each CMC_extension structure in the array, the caller must call cmc_free for the pointer in the item_reference member of the structure.

CMC does not require explicit release of a data extension structure, because CMC releases such structures along with the structures that contain them. For example, CMC implicitly releases the message extension array created by the cmc_read function when calling cmc_free for the enclosing CMC_message structure.

See Also

cmc_act_on, cmc_free, CMC_message, cmc_read


CMC_flags

CMC_flags is a CMC data type that is a bitmask of flags.

Quick Info

Header file: XCMC.H

typedef          CMC_uint32     CMC_flags;

Remarks

A bitmask of this type contains 32 flag bits. The CMC implementation reserves the upper 16 bits for definition by the CMC specification. Any unused bits among the upper 16 must be clear. The implementation reserves the lower 16 flag bits for definition by a CMC data extension.

The meanings of these CMC flags depend on the context in which the client application uses them. CMC reserves all undocumented flags. Unspecified flags should always be set to zero.


CMC_message

A CMC_message structure contains information about a CMC message.

Quick Info

Header file: XCMC.H

typedef struct {
     CMC_message_reference     *message_reference;
     CMC_string     message_type;
     CMC_string subject;
     CMC_time      time_sent;
     CMC_string text_note;
     CMC_recipient *recipients;
     CMC_attachment     *attachments;
     CMC_flags message_flags;
     CMC_extension *message_extensions;
} CMC_message;

Members

message_reference
Pointer to the message reference, which is a counted string — that is, a CMC_counted_string structure. The message reference is a unique identifier for a message within a mailbox.
message_type
Pointer to a string that identifies the type of the message. Three different string identifiers are available:
  • Object identifiers, which are used for message types identified by object identifiers as defined in CCITT Recommendation X.208.
  • CMC registered values, which are used for message types defined in the CMC specification.
  • Bilaterally defined values, which are used for message types that are unregistered. CMC does not ensure that bilaterally defined values are unique.

For the complete specification of CMC message types, see "Remarks."

subject
Pointer to a string describing the subject of the message.
time_sent
The CMC_time structure containing the date and time when the client application submits the message to the CMC implementation.
text_note
Pointer to the string containing the message text. If the value of this member is NULL, there is no message text. If the CMC_MSG_TEXT_NOTE_AS_FILE flag is set for the message_flags member, the message text is in the first attachment to the message. For information on message text format, see "Remarks."
recipients
Pointer to the first element in an array of CMC_recipient structures defining the message recipients.
attachments
Pointer to the first element in an array of CMC_attachment structures defining the attachments to the message.
message_flags
Bitmask of message flags. The following flags can be set:
CMC_MSG_LAST_ELEMENT
The last element in an array of CMC_message structures. The structure with this flag set must be at the end of the array. If this flag is set to zero for any structure, that structure is not the last array element.
CMC_MSG_READ
The message has been read. If this flag is set to zero, the message has not been read.
CMC_MSG_TEXT_NOTE_AS_FILE
The text_note member is ignored and the message text is contained in the file referred to by the first attachment. If this flag is set to zero, the message text is contained in the text_note member.
CMC_MSG_UNSENT
The client application has not sent the message, for example when the message is a draft. The sender can create such a message with the CMC_X_COM_SAVE_MESSAGE data extension. If this flag is set to zero, the client application has sent the message.
message_extensions
Pointer to the first structure in an array of CMC_extension structures representing the message extensions.

Remarks

Message types are used to distinguish between various sorts of messages that might require different processing. For example, the message type might be used by the client application to determine how to display the message or by CMC to determine how to send the message.

CMC message types possible in the message_type member of a CMC_message structure can have the following formats and are case-insensitive.

"OID: " + object_identifier
"CMC: " + cmc_registered_value
"BLT: " + string

An object_identifier is a string containing a series of whitespace separated integers. See CMC_object_identifier for details.

The following is a list of message types:

IPM
Interpersonal message. An interpersonal message is a memo-like message containing a recipient list, an optional subject, an optional text note, and zero or more attachments. The CMC_message structure is optimized to accommodate a message with the registered value IPM.
IP RN
Read notification for an interpersonal message. A read notification indicates the recipient has opened a message.
IP NRN
Nonread notification for an interpersonal message. A nonread notification indicates a message has been removed from the recipient's mailbox without being opened. For instance, the service or user has discarded the message or it has been automatically forwarded to another recipient.
DR
Delivery report. A delivery report indicates the service was able to deliver a message to its recipient.
NDR
Nondelivery report. A nondelivery report indicates the message service was not able to deliver a message to its recipient.

Bilaterally defined values are arbitrary strings and are used to identify custom message types used by the client application.

As the syntax preceding indicates, the OID: type identifier indicates a type identified by an object identifier, the CMC: type identifier indicates a type identified by a CMC registered value, and the BLT: type identifier indicates a type identified by a bilaterally defined value. Following are examples of valid type identifiers:

OID: 1 2 840 113556 3 2 850
CMC: IPM
BLT: my special message type

You can format type identifiers as you choose; the CMC implementation also defines a canonical type identifier format that allows a client application to easily compare type identifier strings. The CMC implementation always returns type identifiers in this format, which guarantees the following:

  • All tokens are separated with a single space.
  • The type identifiers OID:, CMC:, and BLT: are returned in uppercase.

The CMC specification does not define what it will do with type identifier strings that are not in this format.

The formats of messages with the preceding registered values within a CMC_message structure depend on the messaging protocols employed by the underlying messaging system. Often, non-IPM messages take the form of a program-generated message, which follows a memo-like format similar to an IPM format but serves instead to convey information about a previously sent message.

Note The cmc_registered_value types correspond to X.400 message types; however, non-X.400 messaging systems can also use them. Thus, these message types are meant to apply generically and not specifically to X.400 services.

Some implementations only support the interpersonal message type (CMC: IPM). Some implementations might treat messages of types other than IPM as IPM messages or might generate an error for such messages.

For the text_note member, the format of the message text is a sequence of paragraphs, whether it is passed in memory or in a file. Each paragraph is terminated with the appropriate line terminator for the platform: CR (carriage return) for Macintosh, LF (linefeed) for UNIX, and CR/LF for MS-DOS and Windows. The CMC implementation can word-wrap long lines (paragraphs). There is no guarantee that paragraph formatting will remain constant when a message is saved and read back. For example, the cmc_read function can return a long paragraph as a series of shorter paragraphs.

See Also

CMC_attachment, CMC_extension, CMC_recipient, cmc_send, CMC_time


CMC_message_reference

A CMC_message_reference structure is a CMC_counted_string structure containing a message reference, which is the identifier for a message within a message store.

Quick Info

Header file: XCMC.H

typedef          CMC_counted_string     CMC_message_reference;

Remarks

The CMC implementation only guarantees the message reference to be valid for the life of the session. The message reference is specific to the message store; CMC does not guarantee that the reference has any correspondence to a message identifier used by the underlying messaging system. Only during the current session can the client application expect the message reference to refer to the same message.


CMC_message_summary

A CMC_message_summary structure contains a summary of a message. A message summary includes the type of the message, a reference to it for later retrieval, the size of the message, and other information. Message summaries are useful for previewing messages on low-bandwidth networks without actually retrieving the entire message.

Quick Info

Header file: XCMC.H

typedef struct {
     CMC_message_reference     *message_reference;
     CMC_string     message_type;
     CMC_string     subject;
     CMC_time      time_sent;
     CMC_uint32     byte_length;
     CMC_recipient     *originator;
     CMC_flags     summary_flags;
     CMC_extension     *message_summary_extensions;
} CMC_message_summary;

Members

message_reference
Pointer to the message reference, a CMC_counted_string structure containing the mailbox identifier for a message. The message reference is unique within a mailbox.
message_type
  • Pointer to a string that identifies the type of the message. See CMC_message for details.
subject
Pointer to a string containing the subject of the message.
time_sent
A CMC_time structure containing the date and time when the client application submits the message to the CMC implementation.
byte_length
The message size, in bytes. The value should include the size of all the associated features of the message such as attachments and envelope and heading fields. A client application can supply an approximate message size, or if the message size is unknown or unavailable, the value CMC_LENGTH_UNKNOWN.
originator
Pointer to a CMC_recipient structure indicating the message sender.
summary_flags
Bitmask of message summary flags. The following flags can be set:
CMC_SUM_LAST_ELEMENT
The last structure in an array of CMC_message_summary structures. The structure with this flag set must be at the end of the array. If this flag is set to zero for any structure, that structure is not the last array element.
CMC_SUM_READ
The message has been read. If this flag is set to zero, the message has not been read.
CMC_SUM_UNSENT
The client application has not sent the message, for example when the message is a draft. If this flag is set to zero, the client application has sent the message.
message_summary_extensions
Pointer to the first structure in an array of CMC_extension structures representing the message-summary data extensions, if any.

See Also

CMC_extension


CMC_object_identifier

CMC_object_identifier is a data type that is a CMC object identifier string.

Quick Info

Header file: XCMC.H

typedef          CMC_string     CMC_object_identifier;

Remarks

An identifier of this type is globally unique. Its syntax must match the format defined in CCITT Recommendation X.208. This syntax is:

object_identifier          ::= object_id_component*
object_id_component          ::= integer

Namely, the object identifier is a sequence of whitespace separated integers.

The following is an example of an object identifier:

1 2 840 113556 3 2 850

Note The format of the object identifier string is the same as that used in the OID message type. For more information on message types, see CMC_message.

See Also

CMC_message


CMC_recipient

A CMC_recipient structure contains information about a messaging user, either a message recipient or the message sender.

Quick Info

Header file: XCMC.H

typedef struct {
     CMC_string     name;
     CMC_enum      name_type;
     CMC_string     address;
     CMC_enum role;
     CMC_flags recip_flags;
     CMC_extension *recip_extensions;
} CMC_recipient;

Members

name
Pointer to a string that identifies the recipient or sender display name. When the CMC implementation resolves the name to an address, it determines whether it should interpret the name as the name of an individual first and then as the name of a group if the individual name is not found, or vice versa, according to the value of the name_type member.
name_type
Enumeration that indicates whether the structure contains information for a message recipient or a message sender. Possible values are:
CMC_TYPE_GROUP
The recipient or sender name belongs to a distribution list.
CMC_TYPE_INDIVIDUAL
The recipient or sender name belongs to an individual messaging user.
CMC_TYPE_UNKNOWN
An unknown recipient or originator name.

The name_type member is meaningful only if the name member is present. The CMC implementation sets name_type on output. On input, the name_type information can be used by the addressing mechanism in the message service to optimize resolution of the name.

address
Pointer to a recipient or sender address string in a format recognized by the underlying messaging system. CMC does not define the format of the string. This member therefore accommodates any string notations supported by the CMC implementation, as configured at installation.
role
Enumeration that indicates the role of the message recipient or sender. Possible values are:
CMC_ROLE_AUTHORIZING_USER
The user authorizing the message, in cases of messages sent by proxy or in the name of another user.
CMC_ROLE_BCC
A blind carbon copy (BCC) recipient.
CMC_ROLE_CC
A carbon copy (CC) recipient.
CMC_ROLE_ORIGINATOR
The sender of the message.
CMC_ROLE_TO
A primary recipient.
recip_flags
Bitmask of recipient flags. The following flags can be set:
CMC_RECIP_IGNORE
CMC should ignore the specified recipient. This flag is useful for reusing an incoming message's recipient list for a reply. If this flag is set to zero, it indicates that the recipient should not be ignored.
CMC_RECIP_LAST_ELEMENT
The last structure in an array of CMC_recipient structures. The structure with this flag set must be at the end of the array. If this flag is set to zero for any structure, that structure is not the last array element.
CMC_RECIP_LIST_TRUNCATED
CMC has not written all recipient or originator structures requested. The client application uses this flag only for the cmc_look_up function when the complete list of recipients matching the search name cannot be written. The function only sets this flag in the last structure in the array of CMC_recipient structures. If the flag is set to zero, cmc_look_up has written a complete recipient array.
recip_extensions
Pointer to the first structure in an array of CMC_extension structures that contain the recipient or sender data extensions, if any.

Remarks

If the underlying messaging system does not support carbon copy recipients, CMC can convert such a recipient to a primary recipient. Services that cannot support blind carbon-copy recipients should reject messages containing them. If a user designates the same recipient in more than one role, the client application should place multiple recipient entries in the recipient list, each differing from the others in role.

On output, the CMC implementation writes an array of CMC_recipient structures in a specific order. The message sender's structure should be the first element in the array, followed by the primary, carbon copy, and blind carbon-copy recipient structures grouped together in that order. If there is an authorizing user structure, it should be the final element in the array. The CMC implementation does not require ordering of the CMC_recipient structures on input.

See Also

CMC_extension, cmc_look_up


CMC_return_code

CMC_return_code is a data type that is a 32-bit value returned by a CMC function.

Quick Info

Header file: XCMC.H

typedef      CMC_uint32          CMC_return_code;

Remarks

A nonzero return value for a CMC function indicates an error and is associated with one of the defined CMC return values. A return value of zero for a function indicates success. The CMC implementation reserves values in the low-order 16 bits of the return value for standard CMC-defined error values. The high-order 16 bits of the return value are reserved for error values that are defined specifically for the implementation.

CMC client applications can resolve errors within the scope of the CMC implementation. For example, a client application can resolve errors by prompting the user with a dialog box defined through the CMC user interface. If the error remains unresolved after the dialog box has closed, CMC sets the CMC_ERROR_UI_DISPLAYED flag in the return value to indicate that a dialog box regarding the error has already been displayed.


CMC_session_id

CMC_session_id is a data type that is a 32-bit CMC session handle.

Quick Info

Header file: XCMC.H

typedef      uint32          CMC_session_id;

Remarks

The context identified by the session handle contains information about the current session, such as the character set in use and handles for any open sessions with underlying message services. The cmc_logon function creates the CMC session handle, and the cmc_logoff function invalidates it.

See Also

cmc_logoff, cmc_logon


CMC_string

CMC_string is a CMC data type that is a pointer to a character string.

Quick Info

Header file: XCMC.H

typedef      char      *CMC_string;

Remarks

By default, the CMC implementation interprets the string that this data type points to as a null-terminated array of characters. The chosen character set determines the width of a character and the corresponding null-terminating character.

If a client application uses counted strings instead of null-terminated strings, it must set the CMC_COUNTED_STRING_TYPE flag in the logon_flags parameter when logging onto a MAPI session through cmc_logon. The data pointed to by a string of type CMC_string is then defined as a CMC_counted_string structure.

To determine the character set of characters in the string, the CMC implementation looks at the character set in the session attributes, which are chosen by the client application when the call to cmc_logon is made. CMC always attempts to map all strings passed to the client application to the character set for the session. If the client application has not called cmc_logon and is using an implicit session, the CMC implementation interprets input strings by using its default character set.

See Also

CMC_counted_string, cmc_logon


CMC_time

A CMC_time structure contains a time value in CMC-compatible form for use in a message.

Quick Info

Header file: XCMC.H

typedef struct{
     CMC_sint8     second;
     CMC_sint8     minute;
     CMC_sint8     hour;
     CMC_sint8     day;
     CMC_sint8     month;
     CMC_sint8     year;
     CMC_sint8     isdst;
     CMC_sint8      unused1;
     CMC_sint16     tmzone;
     CMC_sint16     unused2;
} CMC_time;

Members

second
Seconds; possible values range from 0 through 59.
minute
Minutes; possible values range from 0 through 59.
hour
Hours since midnight; possible values range from 0 through 23.
day
Day of the month; possible values range from 1 through 31.
month
Months since January; possible values range from 0 through 11.
year
Years since 1900.
isdst
Value for daylight saving time. A nonzero value means daylight saving time is in force.
unused1
Reserved. Do not use.
tmzone
Time zone, measured in minutes relative to Greenwich mean time. The value CMC_NO_TIMEZONE indicates that time zone information is not available.
unused2
Reserved. Do not use.

Remarks

The CMC time implementation is based on the assumption that all time values reflect the appropriate local time. For example, the time_sent members in the CMC_message and CMC_message_summary structures reflect the local time of the sender's location.

See Also

CMC_message, CMC_message_summary


CMC_ui_id

CMC_ui_id is a data type that is a CMC user interface handle.

Quick Info

Header file: XCMC.H

typedef CMC_uint32          CMC_ui_id;

Remarks

The CMC implementation uses a data value of this type for passing user interface information to CMC functions. For example, in a Windows-based operating environment, the parent window handle for the client application is a data value of this type.

A value of NULL for CMC_ui_id is always valid. The CMC implementation defines a default behavior. For example, some implementations might treat NULL as a request to use a user interface defined within the implementation, while other implementations might not have any internally defined interface at all.


CMC_X_COM_configuration

A CMC_X_COM_configuration structure contains configuration data written by the cmc_query_configuration function for the CMC_X_COM_CONFIG_DATA data extension.

Quick Info

Header file: XCMCEXT.H

typedef struct {
     CMC_uint16          ver_spec;
     CMC_uint16          ver_implem;
     CMC_object_identifier     *character_set;
     CMC_enum               line_term;
     CMC_string          default_service;
     CMC_string          default_user;
     CMC_enum               req_password;
     CMC_enum               req_service;
     CMC_enum               req_user;
     CMC_boolean          ui_avail;
     CMC_boolean          sup_nomkmsgread;
     CMC_boolean          sup_counted_str;
} CMC_X_COM_configuration;

Members

ver_spec
A CMC specification version number.
ver_implem
A CMC version number multiplied by 100. For example, version 1.00 is represented as 100.
character_set
Pointer to a CMC_object_identifier structure.
line_term
Enumeration that indicates the type of line delimiter for the message text in a CMC_message. Possible values are:
CMC_LINE_TERM_CRLF
The line delimiter is a carriage return followed by a line feed.
CMC_LINE_TERM_LF
The line delimiter is a line feed.
CMC_LINE_TERM_CR
The line delimiter is a carriage return.
default_service
Pointer to a string identifying the default message service.
default_user
Pointer to a string identifying the default user name of the user accessing the CMC implementation. This default can be used when prompting the user for a user name.
req_password
Enumeration that indicates if a password is required to access the service. Possible values are:
CMC_REQUIRED_NO
No password is required.
CMC_REQUIRED_YES
A password is required.
CMC_REQUIRED_OPT
A password is optional.
req_service
Enumeration that indicates if the message service name is required for logon. Possible values are:
CMC_REQUIRED_NO
No service name is required.
CMC_REQUIRED_YES
A service name is required.
CMC_REQUIRED_OPT
A service name is optional.
req_user
Enumeration that indicates if the messaging user name is required for logon. Possible values are:
CMC_REQUIRED_NO
No user name is required.
CMC_REQUIRED_YES
A user name is required.
CMC_REQUIRED_OPT
A user name is optional.
ui_avail
Boolean value that is TRUE if the CMC implementation in use provides a user interface and FALSE otherwise.
sup_nomkmsgread
Boolean value that indicates whether the cmc_read function supports not marking messages as read. The value is TRUE if the cmc_read function supports the CMC_DO_NOT_MARK_AS_READ flag and FALSE otherwise.
sup_counted_str
Boolean value that indicates whether the cmc_logon function supports the use of the CMC_counted_string type. The value is TRUE if the cmc_logon function supports the CMC_COUNTED_STRING_TYPE flag and FALSE otherwise.

Remarks

The cmc_query_configuration function writes a value into the buffer pointed to by its reference parameter. That value is a copy of a particular member of the CMC implementation's CMC_X_COM_configuration structure, depending on the value the client application passes for the item parameter. For example, to see whether the CMC implementation defines its own user interface for logon and error resolution, the client application should use CMC_CONFIG_UI_AVAIL as the value of item. When cmc_query_configuration returns, the CMC_buffer pointed to by reference will contain TRUE or FALSE to indicate whether an interface is available. The client application must ensure that the reference parameter points to a buffer of sufficient size to hold the type of data that the item parameter specifies.

See Also

cmc_free, cmc_logon, CMC_object_identifier, cmc_query_configuration, cmc_read, CMC_X_COM_CONFIG_DATA


CMC_X_COM_support

A CMC_X_COM_support structure contains information about MAPI support for a particular CMC data extension or extension set, and is used in an array pointed to by the item_reference member of a CMC_extension structure.

Quick Info

Header file: XCMCEXT.H

typedef struct {
     CMC_uint32 item_code;
     CMC_flags flags;
} CMC_X_COM_support;

Members

item_code
Code for the CMC data extension whose support the client application is querying about. The client application sets this member during calls to the cmc_logon and cmc_query_configuration functions. The possible extensions are:
CMC_XS_COM CMC_X_COM_ATTACH_CHARPOS
CMC_X_COM_CAN_SEND_RECIP CMC_X_COM_CONFIG_DATA
CMC_X_COM_PRIORITY CMC_X_COM_RECIP_ID
CMC_X_COM_SAVE_MESSAGE CMC_X_COM_SENT_MESSAGE
CMC_X_COM_SUPPORT_EXT CMC_X_COM_TIME_RECEIVED
CMC_XS_MS CMC_X_MS_ADDRESS_UI
CMC_X_MS_ATTACH_DATA CMC_X_MS_FUNCTION_FLAGS
CMC_X_MS_MESSAGE_DATA CMC_X_MS_SESSION_FLAGS

flags
Bitmask of extension code flags. The following flags can be set:
CMC_X_COM_SUP_EXCLUDE
On input this flag removes the item represented by the value of the item_code member from consideration when deciding whether the implementation supports an extension set. If this flag is set on input for the cmc_logon function, the implementation will not attach the item to extension structures for this session even if other entries request it. If this flag is set on input, then none of the remaining flags in this list will be set on output.
CMC_X_COM_SUPPORTED
The CMC implementation supports the item represented by the item_code member. For whole extension sets (for example, CMC_XS_COM), this flag indicates the CMC implementation supports all the function and structure extensions in the set.
CMC_X_COM_NOT_SUPPORTED
The CMC implementation does not support the item represented by the item_code member. If this flag applies to a whole extension set containing both function and structure extensions, it indicates the CMC implementation does not support some or all function and structure extensions in the set. If this flag applies to a structure extension or an extension set containing structure extensions, it indicates the CMC implementation will not attach the structure extensions to structures for this session.
CMC_X_COM_DATA_EXT_SUPPORTED
The CMC implementation supports all requested structure extensions for an extension set. The client application must request function extensions separately. When the cmc_logon function returns this flag, the implementation will attach structure extensions to structures for this session.
CMC_X_COM_FUNC_EXT_SUPPORTED
The CMC implementation supports all requested function extensions for an extension set. The client application must request structure extensions separately. Unlike the CMC_X_COM_SUPPORTED flag, if the cmc_logon function returns this flag, structure extensions will not be attached to structures for this session and must be requested separately.

See Also

CMC_extension, cmc_logon, CMC_X_COM_SUPPORT_EXT


CMC_X_MS_ATTACH

CMC_X_MS_ATTACH data structures are used by the CMC_X_MS_ATTACH_DATA and CMC_X_MS_ATTACH_MESSAGE extensions to support message attachments.

Quick Info

Header file: XCMCMSX2.H

typedef struct {
     CMC_message_reference FAR * message;
     CMC_uint32 id;
     CMC_buffer object;
} CMC_X_MS_ATTACH;


Data Extensions

The functionality of the CMC data structures and functions can be augmented through the use of CMC data extensions. Data extensions are used to add additional fields to data structures and additional parameters to a function.

A standard generic data structure, CMC_extension, specifies the item code, item data, item reference, and a bitmask of flags. The item code is the name of the extension and is used to identify it. The item data, depending on the item code, contains either the length of the item value, the item value itself, or other information about the item. The item reference points to where the extension value is stored or is NULL if there is no related item storage. The flags are set to zero or to values that describe options for the extension. To use an extension in a CMC function, a client application sets the item code member of a CMC_extension structure to a valid name and passes the structure as part of the parameter list.

Extensions that are additional parameters to a function can be either input or output parameters. If the extension is passed as an input parameter, the calling client application or service provider allocates memory for the CMC_extension structure and any other structures that are associated with the extension. If the extension is passed as an output parameter, CMC allocates the storage for the extension result and the caller frees it by calling the cmc_free function.

The following extensions make up the CMC common extension set, the extensions that are common to most CMC implementations but are not in the CMC base specification. The extensions are listed in alphabetical order. Each reference entry describes the purpose of the extension.


CMC_XS_COM

CMC_XS_COM is a CMC extension identifier used for all extensions in the common extension set, that is the extensions that are common to most CMC implementations but are not in the CMC base specification. For a complete list of common extensions, see CMC_X_COM_support.

Quick Info

Header file: XCMCEXT.H

See Also

cmc_logon, cmc_query_configuration, CMC_X_COM_SUPPORT_EXT


CMC_X_COM_ATTACH_CHARPOS

CMC_X_COM_ATTACH_CHARPOS is a CMC extension that supports display of a graphical representation (usually an icon) of an attachment in the message text. The extension holds the character position for the representation.

Quick Info

Header file: | XCMCEXT.H
Adds to: | CMC_attachment structure

Input Usage

item_data
Zero-based character offset of the attachment within the message text. Note that this offset is a character offset, not a byte offset — an important distinction when multibyte character sets are in use.
item_reference
NULL.
extension_flags
All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data
Zero-based character offset of the attachment.
item_reference
Unchanged.
extension_flags
Unchanged.

Remarks

At logon, CMC passes the CMC_X_COM_ATTACH_CHARPOS item_data member and any flags in a CMC_X_COM_support structure. Doing so indicates that CMC supports the CMC_X_COM_ATTACH_CHARPOS extension and that the client application can attach a CMC_extension containing an item code and a graphic representation to the CMC_attachment structure during the session.

See Also

CMC_attachment, CMC_extension, CMC_X_COM_support


CMC_X_COM_CAN_SEND_RECIP

CMC_X_COM_CAN_SEND_RECIP is a CMC extension that checks whether the message service is ready to send to the specified recipient.

Quick Info

Header file: | XCMCEXT.H
Adds to: | cmc_look_up function

Input Usage

item_data
Zero.
item_reference
NULL. On input to the cmc_look_up function, the recipient_in parameter contains the recipient about which the message service is being queried. If there is more than one recipient passed in recipient_in, cmc_look_up only looks at the first recipient.
extension_flags
All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data
Bitmask of extension flags. The following flags can be set:
CMC_X_COM_DEFER
The service provider will accept the message but defer it until a transport provider is ready.
CMC_X_COM_NOT_READY
No transport provider is available for the specified recipient type.
CMC_X_COM_READY
The message can be sent immediately.
item_reference
Unchanged.
extension_flags
Unchanged.

See Also

CMC_extension, cmc_look_up


CMC_X_COM_CONFIG_DATA

CMC_X_COM_CONFIG_DATA is a CMC extension that obtains all available configuration information.

Quick Info

Header file: | XCMCEXT.H
Adds to: | cmc_query_configuration function

Input Usage

item_data
Zero.
item_reference
NULL.
extension_flags
All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data
Unchanged.
item_reference
Pointer to a CMC_X_COM_configuration structure containing all the information available from the cmc_query_configuration function.
extension_flags
Bitmask of extension flags. If the call successfully returns a structure, the function sets the CMC_EXT_OUTPUT flag.

Remarks

The buffer pointed to by the item_reference member should be freed with one call to cmc_free.

See Also

CMC_extension, cmc_query_configuration, CMC_X_COM_configuration


CMC_X_COM_PRIORITY

CMC_X_COM_PRIORITY is a CMC extension indicating message priority.

Quick Info

Header file: XCMCEXT.H

Input Usage

item_data
Bitmask of extension flags. The following flags can be set:
CMC_X_COM_LOW
Indicates a low priority for the message.
CMC_X_COM_NORMAL
Indicates a normal priority for the message.
CMC_X_COM_URGENT
Indicates a high priority for the message.
item_reference
NULL.
extension_flags
All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data
Bitmask of extension flags that describe the urgency of the message. The following flags can be set:
CMC_X_COM_LOW
A low priority for the message.
CMC_X_COM_NORMAL
A normal priority for the message.
CMC_X_COM_URGENT
A high priority for the message.
item_reference
Unchanged.
extension_flags
Unchanged.

Adds to

The CMC_message and CMC_message_summary structures.

Remarks

At logon, the caller passes CMC_X_COM_PRIORITY in the CMC_X_COM_SUPPORT_EXT extension to indicate that this extension should be attached to the CMC_message and CMC_message_summary structures during the session.

See Also

CMC_extension, CMC_message, CMC_message_summary, CMC_X_COM_SUPPORT_EXT.


CMC_X_COM_RECIP_ID

CMC_X_COM_RECIP_ID is a CMC extension that adds a unique recipient identifier to a CMC_recipient structure. A recipient identifier is an opaque object that the underlying messaging system uses to uniquely represent a recipient, and can be thought of as the result of resolving an address.

Quick Info

Header file: XCMCEXT.H

Input Usage

item_data
The length in bytes of the recipient identifier.
item_reference
Pointer to the recipient identifier.
extension_flags
All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data
The length in bytes of the recipient identifier.
item_reference
Pointer to the recipient identifier.
extension_flags
Unchanged.

Adds to

The CMC_recipient structure.

Remarks

The CMC implementation handles the CMC_X_COM_RECIP_ID extension during recipient name resolution. The client application can use this to avoid further name resolution during sending. Some message services allow the client application to reuse the recipient identifier returned by a previous call to cmc_look_up. The client application can attach it to a recipient structure that the service provider would otherwise try to resolve.

At logon, the client application passes the item_code member of CMC_X_COM_RECIP_ID in the CMC_X_COM_SUPPORT_EXT array to request that the CMC implementation should attach recipent identifiers to CMC_recipient structures during the session.

See Also

CMC_extension, CMC_recipient, CMC_X_COM_support


CMC_X_COM_SAVE_MESSAGE

CMC_X_COM_SAVE_MESSAGE is a CMC extension that saves a message (that is, a CMC_message structure) to the receive folder (the Inbox).

Quick Info

Header file: XCMCEXT.H

Input Usage

item_data
Zero.
item_reference
Pointer to the CMC_message structure to save to the receive folder. To indicate that an unsent message has not been sent, the CMC implementation sets the CMC_MSG_UNSENT flag in the message_flags member of the CMC_message structure. To indicate that the operation to be performed (save to receive folder) is contained in a CMC_X_COM_SAVE_MESSAGE extension, the cmc_act_on function's operation parameter must be set to the CMC_ACT_ON_EXTENDED flag.
extension_flags
All flags used with the CMC_extension structure are valid. No further flags are defined. To indicate that the CMC implementation should carry out a save action rather than a deletion, the flag CMC_EXT_REQUIRED must be set in the extension_flags member.

Output Usage

item_data
Unchanged.
item_reference
Pointer to the message reference of the message that was saved to the receive folder (the Inbox). The client application must free the message reference using the cmc_free function.
extension_flags
If cmc_act_on has successfully saved the message and returned the message reference, the CMC_EXT_OUTPUT flag is set.

Adds to

The cmc_act_on function.

See Also

cmc_act_on, CMC_extension, CMC_message, CMC_message_reference


CMC_X_COM_SENT_MESSAGE

CMC_X_COM_SENT_MESSAGE is a CMC extension that creates a CMC_message structure containing information for the message just sent.

Quick Info

Header file: XCMCEXT.H

Input Usage

item_data
Zero.
item_reference
NULL.
extension_flags
All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data
Unchanged.
item_reference
Pointer to a CMC_message structure containing information for the message just sent. The client application must free this pointer by calling the cmc_free function.
extension_flags
The cmc_send function has successfully put a pointer to a CMC_message structure in the item_reference parameter if the CMC_EXT_OUTPUT flag is set.

Adds to

The cmc_send function.

Remarks

CMC_X_COM_SAVE_MESSAGE is used to obtain information about a message that has just been sent when some or all of the members of the CMC_message structure are set by the user interface defined by the CMC implementation rather than by the client application before the cmc_send call.

See Also

CMC_extension, cmc_free, CMC_message, cmc_send


CMC_X_COM_SUPPORT_EXT

CMC_X_COM_SUPPORT_EXT is a CMC extension that client applications use to query the CMC implementation about the extensions it supports. If the implementation supports any extensions, it must support CMC_X_COM_SUPPORT_EXT.

Quick Info

Header file: XCMCEXT.H

Input Usage

item_data
The number of items in an array pointed to by the item_reference member.
item_reference
Pointer to the first element in an array of CMC_X_COM_support structures listing extensions the client application requests the CMC implementation to support. See CMC_X_COM_support for details.
extension_flags
All flags used with CMC are valid. No further flags are defined.

Output Usage

item_data
Unchanged.
item_reference
Pointer to an array of CMC_X_COM_support structures where the CMC implementation sets the flags in the flags member to indicate support for the requested extensions. The implementation does not set these flags if CMC_X_COM_SUP_EXCLUDE was set on input. See CMC_X_COM_support for details.
extension_flags
Unchanged.

Adds to

The cmc_query_configuration and cmc_logon functions.

Remarks

Client applications can use this extension before establishing a session to get preliminary information about support before logging on. When a client application uses the extension with cmc_logon, it indicates which data extensions the client wants added to the data structures for the session.

Note The CMC implementation supports different extensions, based on the service with which the client application creates a session. Thus client applications should use CMC_X_COM_SUPPORT_EXT at logon to verify extension support.

See Also

CMC_extension, cmc_logon, cmc_query_configuration, CMC_X_COM_support


CMC_X_COM_TIME_RECEIVED

CMC_X_COM_TIME_RECEIVED is a CMC extension that provides a CMC_time structure containing the delivery time of a message.

Quick Info

Header file: XCMCEXT.H

Input Usage

CMC ignores this extension on input.

Output Usage

item_data
Zero.
item_reference
Points to the CMC_time structure containing the time the message was received.
extension_flags
NULL.

Adds to

The CMC_message and CMC_message_summary structures.

Remarks

At logon, the client application passes the CMC_X_COM_TIME_RECEIVED extension in the CMC_X_COM_SUPPORT_EXT array to indicate that the CMC implementation should attach this extension to CMC_message and CMC_message_summary structures during the session.

See Also

CMC_extension, CMC_message, CMC_message_summary, CMC_time, CMC_X_COM_support


CMC_XS_MS

CMC_XS_MS is a CMC extension identifier used for all extensions in the Microsoft extension set. For a full list of Microsoft extensions, see CMC_X_COM_support.

Quick Info

Header file: XCMCMSXT.H

See Also

cmc_logon, cmc_query_configuration, CMC_X_COM_SUPPORT_EXT


CMC_X_MS_ADDRESS_UI

CMC_X_MS_ADDRESS_UI is a CMC extension that adds options to the address-book dialog box.

Quick Info

Header file: XCMCMSXT.H

Input Usage

item_data
The number of edit boxes in the dialog box.
item_reference
Pointer to an array of two CMC_string data types. The first string is the caption for the address-book dialog box. To not provide a label, the client application sets the label string to NULL. The second string is a label for the recipient well if there is only one recipient well. If there are multiple recipient wells (for example, TO: and CC:) this string is ignored.
extension_flags
All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data
Unchanged.
item_reference
Unchanged.
extension_flags
Unchanged.

Adds to

The cmc_look_up function.

See Also

CMC_extension, cmc_look_up


CMC_X_MS_ATTACH_DATA

CMC_X_MS_ATTACH_DATA is a CMC extension that contains bitmasks of flags used to provide data on message attachments.

Quick Info

Header file: XCMCMSXT.H

Input Usage

item_data
Bitmask of attachment flags. The following flags can be set:
CMC_X_MS_ATTACH_OLE
The CMC implementation supports OLE attachments.
CMC_X_MS_ATTACH_OLE_STATIC
The CMC implementation supports static OLE attachments.
CMC_X_MS_ATTACH_MESSAGE
The CMC implementation supports attached messages.
item_reference
Object identifier for the attachment encoding. This member can point to a CMC_X_MS_ATTACH structure, to allow a message reference to be added as an embedded message in the current message.
extension_flags
All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data
Bitmask of attachment flags. CMC can set the following flags:
CMC_X_MS_ATTACH_OLE
The CMC implementation supports OLE attachments.
CMC_X_MS_ATTACH_OLE_STATIC
The CMC implementation supports static OLE attachments.
CMC_X_MS_ATTACH_MESSAGE
The CMC implementation supports attached messages.
item_reference
Object identifier for the attachment encoding.
extension_flags
Unchanged.

Adds to

The CMC_attachment structure.

See Also

CMC_attachment, CMC_extension


CMC_X_MS_FUNCTION_FLAGS

CMC_X_MS_FUNCTION_FLAGS is a CMC extension that contains a bitmask of flags used for CMC functions that serve purposes other than session handling.

Quick Info

Header file: XCMCMSXT.H

Input Usage

item_data
Bitmask of extension flags. The following flags can be set:
CMC_X_MS_AB_NO_MODIFY
Disallows changes to the address book through the address-book details dialog box if a user interface is being used with the cmc_look_up function.
CMC_X_MS_LIST_GUARANTEE_FIFO
Causes the CMC implementation to return messages in date order when the cmc_list function is called.
CMC_X_MS_READ_BODY_AS_FILE
Causes the CMC implementation to put an attachment containing the message text in the message body rather than putting the message text in the message body directly when returning a message with the cmc_read function.
CMC_X_MS_READ_ENV_ONLY
Causes the CMC implementation to return only the message header information when returning a message with the cmc_read function.
item_reference
NULL.
extension_flags
All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

extension_flags
Unchanged.
item_data
Unchanged.
item_reference
Unchanged.

Adds to

The cmc_read, cmc_look_up, and cmc_list functions.

See Also

CMC_extension, cmc_list, cmc_look_up, cmc_read


CMC_X_MS_MESSAGE_DATA

CMC_X_MS_MESSAGE_DATA is a CMC extension that contains a bitmask of flags used to provide extra data about messages.

Quick Info

Header file: XCMCMSXT.H

Input Usage

item_data
Bitmask of extension flags. The following flag can be set:
CMC_X_MS_MSG_RECEIPT_REQ
The message sender requests notification of message receipt.
item_reference
Pointer to a string containing the conversation thread.
extension_flags
All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data
Bitmask of extension flags. The following flag can be set:
CMC_X_MS_MSG_RECEIPT_REQ
The message sender requests notification of message receipt.
item_reference
Unchanged.
extension_flags
Unchanged.

Adds to

The CMC_message structure.

See Also

CMC_extension, CMC_message


CMC_X_MS_SESSION_FLAGS

CMC_X_MS_SESSION_FLAGS is a CMC extension that contains a bitmask of flags used to provide information when logging on and off a session.

Quick Info

Header file: XCMCMSXT.H

Input Usage

item_data
Bitmask of logon and logoff flags. The following flags can be set for use with the cmc_logon function:
CMC_X_MS_NEW_SESSION
The message sender requests a new session instead of requesting use of a shared session.
CMC_X_MS_FORCE_DOWNLOAD
The CMC implementation should attempt to download all new messages before the cmc_logon function returns. If this flag is not set, downloading might take place in the background after cmc_logon returns.

The following flags can be used with the cmc_logoff function:

CMC_X_LOGOFF_SHARED
The CMC implementation should close all shared sessions.
item_reference
NULL.
extension_flags
All flags used with the CMC_extension structure are valid. No further flags are defined.

Output Usage

item_data
Unchanged.
item_reference
Unchanged.
extension_flags
Unchanged.

Adds to

The cmc_logon, cmc_look_up, and cmc_send functions.

See Also

CMC_extension, cmc_list, cmc_logon, cmc_look_up, cmc_send


Simple MAPI

Simple MAPI is a set of functions and related data structures you can use to add messaging functionality to C, C++, or Visual Basic Windows applications. The Simple MAPI functions are available in C and C++ and Visual Basic versions.

The following table provides an overview of the Simple MAPI functions.

Simple MAPI function | Description
MAPIAddress | Addresses a message.
MAPIDeleteMail | Deletes a message.
MAPIDetails | Displays a recipient-details dialog box.
MAPIFindNext | Returns the identifier of the first or next message of a specified type.
MAPIFreeBuffer | Frees memory allocated by the messaging system.
MAPILogoff | Ends a session with the messaging system.
MAPILogon | Establishes a messaging session.
MAPIReadMail | Reads a message.
MAPIResolveName | Displays a dialog box to resolve an ambiguous recipient name.
MAPISaveMail | Saves a message.
MAPISendDocuments | Sends a standard message using a dialog box.
MAPISendMail | Sends a message, allowing greater flexibility than MAPISendDocuments in message generation.

To use the Simple MAPI functions, compile your source code with MAPI.H. MAPI.H contains definitions for all of the functions, return value constants, and data types. To call a Simple MAPI function, load MAPI.DLL and use the Win32 GetProcAddress function to acquire an entry point. The function calling conventions should be FAR PASCAL.

All strings passed to all MAPI calls and returned by all MAPI calls are null-terminated and must be specified in the current character set or code page of the caller's operating system process.


Functions for C and C++

The following alphabetical entries contain documentation for the Simple MAPI functions for C and C++.


MAPIAddress

The MAPIAddress function creates or modifies a set of address list entries.

Quick Info

Header file: MAPI.H

ULONG FAR PASCAL MAPIAddress(
  LHANDLE lhSession,
  ULONG ulUIParam,
  LPTSTR lpszCaption,
  ULONG nEditFields,
  LPTSTR lpszLabels,
  ULONG nRecips,
  lpMapiRecipDesc lpRecips,
  FLAGS flFlags,
  ULONG ulReserved,
  LPULONG lpnNewRecips,
  lpMapiRecipDesc FAR * lppNewRecips
)

Parameters

lhSession
[in] Session handle that represents a Simple MAPI session or zero. If the value of the lhSession parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. This temporary session can be an existing shared session or a new one. If necessary, a logon dialog box is displayed.
ulUIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If the ulUIParam parameter contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, ulUIParam is ignored.
lpszCaption
[in] Pointer to the caption for the address list dialog box, NULL, or an empty string. When the lpszCaption parameter is NULL or points to an empty string, MAPIAddress uses the default caption "Address Book."
nEditFields
[in] The number of edit controls that should be present in the address list. The values 0 through 4 are valid. If the value of the nEditFields parameter is 4, each recipient class supported by the underlying messaging system has an edit control. If the value of nEditFields is zero, only address list browsing is possible. Values of 1, 2, or 3 control the number of edit controls present.

However, if the number of recipient classes in the array pointed to by the lpRecips parameter is greater than the value of nEditFields, the number of classes in lpRecips is used to indicate the number of edit controls instead of the value of nEditFields. If the value of nEditFields is 1 and more than one kind of entry exists in lpRecips, then the lpszLabels parameter is ignored.

Entries selected for the different controls are differentiated by the ulRecipClass member in the returned recipient structure.

lpszLabels
[in] Pointer to a string to be used as an edit control label in the address-list dialog box. When the nEditFields parameter is set to any value other than 1, the lpszLabels parameter is ignored and should be NULL or point to an empty string. Also, if the caller requires the default control label "To," lpszLabels should be NULL or point to an empty string.
nRecips
[in] The number of entries in the array indicated by the lpRecips parameter. If the value of the nRecips parameter is zero, lpRecips is ignored.
lpRecips
[in] Pointer to an array of MapiRecipDesc structures defining the initial recipient entries to be used to populate the address-list dialog box. The entries do not need to be grouped by recipient class; they are differentiated by the values of the ulRecipClass members of the MapiRecipDesc structures in the array. If the number of different recipient classes is greater than the value indicated by the nEditFields parameter, the nEditFields and lpszLabels parameters are ignored.
flFlags
[in] Bitmask of option flags. The following flags can be set:
MAPI_LOGON_UI
A dialog box should be displayed to prompt the user to log on if required. When the MAPI_LOGON_UI flag is not set, the client application does not display a logon dialog box and returns an error value if the user is not logged on.
MAPI_NEW_SESSION
An attempt should be made to create a new session rather than acquire the environment's shared session. If the MAPI_NEW_SESSION flag is not set, MAPIAddress uses an existing shared session.
ulReserved
Reserved; must be zero.
lpnNewRecips
[out] Pointer to the number of entries in the lppNewRecips recipient output array. If the value of the lpnNewRecips parameter is zero, the lppNewRecips parameter is ignored.
lppNewRecips
[out] Pointer to an array of MapiRecipDesc structures containing the final list of recipients. This array is allocated by MAPIAddress, cannot be NULL, and must be freed using MAPIFreeBuffer, even if there are no new recipients. Recipients are grouped by recipient class in the following order: MAPI_TO, MAPI_CC, MAPI_BCC.

Return Values

MAPI_E_FAILURE
One or more unspecified errors occurred while addressing the message. No list of recipient entries was returned.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed. No list of recipient entries was returned.
MAPI_E_INVALID_EDITFIELDS
The value of the nEditFields parameter was outside the range of 0 through 4. No list of recipient entries was returned.
MAPI_E_INVALID_RECIPS
One or more of the recipients in the address list was not valid. No list of recipient entries was returned.
MAPI_E_INVALID_SESSION
An invalid session handle was used for the lhSession parameter. No list of recipient entries was returned.
MAPI_E_LOGIN_FAILURE
There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No list of recipient entries was returned.
MAPI_E_NOT_SUPPORTED
The operation was not supported by the underlying messaging system.
MAPI_E_USER_ABORT
The user canceled one of the dialog boxes. No list of recipient entries was returned.
SUCCESS_SUCCESS
The call succeeded and a list of recipient entries was returned.

Remarks

The MAPIAddress function displays a standard address-list dialog box to show an initial set of zero or more recipients. The user can choose new entries to add to the set or make changes to existing entries. This dialog box cannot be suppressed, but the caller can set dialog box characteristics. The changed set of recipients is returned to the caller.

Before MAPIAddress writes new or changed recipient information, it must allocate memory for the structure array that will contain the information. Memory is also allocated as part of preloading the address book, regardless of whether new or changed recipient data is written. Client applications must call the MAPIFreeBuffer function to free this memory after MAPIAddress returns. If any error occurs, no memory was allocated and clients do not need to call MAPIFreeBuffer.

See Also

MAPIFreeBuffer, MAPILogon, MapiRecipDesc


MAPIDeleteMail

The MAPIDeleteMail function deletes a message.

Quick Info

Header file: MAPI.H

ULONG FAR PASCAL MAPIDeleteMail(
  LHANDLE lhSession,
  ULONG ulUIParam,
  LPTSTR lpszMessageID,
  FLAGS flFlags,
  ULONG ulReserved
)

Parameters

lhSession
[in] Session handle that represents a valid Simple MAPI session. The value of the lhSession parameter must represent a valid session; it cannot be zero.
ulUIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If the ulUIParam parameter contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, ulUIParam is ignored.
lpszMessageID
[in] The identifier for the message to be deleted. This identifier is messaging system-specific and will be invalid when MAPIDeleteMail successfully returns.
flFlags
Reserved; must be zero.
ulReserved
Reserved; must be zero.

Return Values

MAPI_E_FAILURE
One or more unspecified errors occurred while deleting the message. No message was deleted.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed. No message was deleted.
MAPI_E_INVALID_MESSAGE
An invalid message identifier was passed in the lpszMessageID parameter. No message was deleted.
MAPI_E_INVALID_SESSION
An invalid session handle was passed in the lhSession parameter. No message was deleted.
SUCCESS_SUCCESS
The call succeeded and the message was deleted.

Remarks

To find the message to be deleted, call the MAPIFindNext function before calling the MAPIDeleteMail function. Because message identifiers are opaque, messaging system-specific, and can be invalidated at any time, MAPIDeleteMail considers a message identifier to be valid only for the current session. MAPIDeleteMail handles invalid message identifiers by returning the MAPI_E_INVALID_MESSAGE value.

See Also

MAPIFindNext, MAPILogon, MAPISaveMail


MAPIDetails

The MAPIDetails function displays a dialog box containing the details of a selected address list entry.

Quick Info

Header file: MAPI.H

ULONG FAR PASCAL MAPIDetails(
  LHANDLE lhSession,
  ULONG ulUIParam,
  lpMapiRecipDesc lpRecip,
  FLAGS flFlags,
  ULONG ulReserved
)

Parameters

lhSession
[in] Session handle that represents a Simple MAPI session or zero. If the value of the lhSession parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. This temporary session can be an existing shared session or a new one. If additional information is required from the user to successfully complete the logon, a dialog box is displayed.
ulUIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If the ulUIParam parameter contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, ulUIParam is ignored.
lpRecip
[in] Pointer to the recipient for which details are to be displayed. MAPIDetails ignores all members of this MapiRecipDesc structure except the ulEIDSize and lpEntryID members. If the value of ulEIDSize is non-zero, MAPIDetails resolves the recipient entry. If the value of ulEIDSize is zero, MAPIDetails returns the MAPI_E_AMBIGUOUS_RECIP value.
flFlags
[in] Bitmask of option flags. The following flags can be set:
MAPI_AB_NOMODIFY
The caller is requesting that the dialog box be read-only, prohibiting changes. MAPIDetails might or might not honor the request.
MAPI_LOGON_UI
A dialog box should be displayed to prompt the user to log on if required. When the MAPI_LOGON_UI flag is not set, the client application does not display a logon dialog box and returns an error value if the user is not logged on.
MAPI_NEW_SESSION
An attempt should be made to create a new session rather than acquire the environment's shared session. If the MAPI_NEW_SESSION flag is not set, MAPIDetails uses an existing shared session.
ulReserved
Reserved; must be zero.

ReturnValues

MAPI_E_AMBIGUOUS_RECIPIENT
The dialog box could not be displayed because the ulEIDSize member of the structure pointed to by the lpRecips parameter was zero.
MAPI_E_FAILURE
One or more unspecified errors occurred. No dialog box was displayed.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed. No dialog box was displayed.
MAPI_E_INVALID_RECIPS
The recipient specified in the lpRecip parameter was unknown or the recipient had an invalid ulEIDSize value. No dialog box was displayed.
MAPI_E_LOGIN_FAILURE
There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No dialog box was displayed.
MAPI_E_NOT_SUPPORTED
The operation was not supported by the underlying messaging system.
MAPI_E_USER_ABORT
The user canceled either the logon dialog box or the details dialog box.
SUCCESS_SUCCESS
The call succeeded and the details dialog box was displayed.

Remarks

The MAPIDetails function presents a dialog box that shows the details of a particular address list entry. The display name and address are the minimum attributes that are displayed in the dialog box; more information can be shown, depending on the address book provider. The details dialog box cannot be suppressed, but the caller can request that it be read-only or modifiable.

Details can only be shown for resolved address list entries. An entry is resolved if the value of the ulEIDSize member of the MapiRecipDesc structure is nonzero. Entries are resolved when they are returned by the MAPIAddress or MAPIResolveName functions and as the result being recipients of read mail.

See Also

MAPIAddress, MAPILogon, MapiRecipDesc, MAPIResolveName


MAPIFindNext

The MAPIFindNext function retrieves the next (or first) message identifier of a specified type of incoming message.

Quick Info

Header file: MAPI.H

ULONG FAR PASCAL MAPIFindNext(
  LHANDLE lhSession,
  ULONG ulUIParam,
  LPTSTR lpszMessageType,
  LPTSTR lpszSeedMessageID,
  FLAGS flFlags,
  ULONG ulReserved,
  LPTSTR lpszMessageID
)

Parameters

lhSession
[in] Session handle that represents a Simple MAPI session. The value of the lhSession parameter must represent a valid session; it cannot be zero.
ulUIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If the ulUIParam parameter contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, ulUIParam is ignored.
lpszMessageType
[in] Pointer to a string identifying the message class to search. To find an interpersonal message (IPM), specify NULL in the lpszMessageType parameter or have it point to an empty string. Messaging systems whose only supported message class is IPM can ignore this parameter.
lpszSeedMessageID
[in] Pointer to a string containing the message identifier seed for the request. If the lpszSeedMessageID parameter is NULL or points to an empty string, MAPIFindNext retrieves the first message that matches the type specified in the lpszMessageType parameter.
flFlags
[in] Bitmask of option flags. The following flags can be set:
MAPI_GUARANTEE_FIFO
The message identifiers returned should be in the order of time received. MAPIFindNext calls can take longer if this flag is set. Some implementations cannot honor this request and return the MAPI_E_NO_SUPPORT value.
MAPI_LONG_MSGID
The returned message identifier can be as long as 512 characters. If this flag is set, the lpszMessageID parameter must be large enough to accomodate 512 characters.

Older versions of MAPI supported smaller message identifiers (64 bytes) and did not include this flag. MAPIFindNext will succeed without this flag set as long as lpszMessageID is large enough to hold the message identifier. If lpszMessageID cannot hold the message identifier, MAPIFindNext will fail.

MAPI_UNREAD_ONLY
Only unread messages of the specified type should be enumerated. If this flag is not set, MAPIFindNext can return any message of the specified type.
ulReserved
Reserved; must be zero.
lpszMessageID
[out] Pointer to the returned message identifier. The caller is responsible for allocating the memory. To ensure compatibility, allocate 512 characters and set MAPI_LONG_MSGID in the flFlags parameter. A smaller buffer is sufficient only if the returned message identifier is always 64 characters or less.

Return Values

MAPI_E_FAILURE
One or more unspecified errors occurred while matching the message type. The call failed before message type matching could take place.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed. No message was found.
MAPI_E_INVALID_MESSAGE
An invalid message identifier was passed in the lpszSeedMessageID parameter. No message was found.
MAPI_E_INVALID_SESSION
An invalid session handle was passed in the lhSession parameter. No message was found.
MAPI_E_NO_MESSAGES
A matching message could not be found.
SUCCESS_SUCCESS
The call succeeded and the message identifier was returned.

Remarks

The MAPIFindNext function allows a client application to enumerate messages of a given type. This function can be called repeatedly to list all messages in the folder. Message identifiers returned from MAPIFindNext can be used in other Simple MAPI calls to retrieve message contents and delete messages. This function is for processing incoming messages, not for managing received messages.

MAPIFindNext looks for messages in the folder in which new messages of the specified type are delivered. MAPIFindNext calls can be made only in the context of a valid Simple MAPI session established with the MAPILogon function.

When the lpszSeedMessageID parameter is NULL or points to an empty string, MAPIFindNext returns the message identifier for the first message of the type specified by the lpszMessageType parameter. When lpszSeedMessageID contains a valid identifier, the function returns the next matching message of the type specified by lpszMessageType. Repeated calls to MAPIFindNext ultimately result in a return of the MAPI_E_NO_MESSAGES value, which means the enumeration is complete.

Message type matching is done against message class strings. All message types whose names match (up to the length specified in lpszMessageType) are returned.

Because message identifiers are messaging system-specific and can be invalidated at any time, message identifiers are valid only for the current session. If the message identifier passed in lpszSeedMessageID is invalid, MAPIFindNext returns the MAPI_E_INVALID_MESSAGE value.

See Also

MAPILogon


MAPIFreeBuffer (Simple MAPI)

The MAPIFreeBuffer function frees memory allocated by the messaging system.

Quick Info

Header file: MAPI.H

ULONG FAR PASCAL MAPIFreeBuffer(
  LPVOID pv
)

Parameters

pv
[in] Pointer to memory allocated by the messaging system. This pointer is returned by the MAPIReadMail, MAPIAddress, and MAPIResolveName functions.

Return Values

MAPI_E_FAILURE
One or more unspecified errors occurred. The memory could not be freed.
SUCCESS_SUCCESS
The call succeeded and the memory was freed.

See Also

MAPILogoff


MAPILogoff

The MAPILogoff function ends a session with the messaging system.

Quick Info

Header file: MAPI.H

ULONG FAR PASCAL MAPILogoff (
  LHANDLE lhSession,
  ULONG ulUIParam,
  FLAGS flFlags,
  ULONG ulReserved
)

Parameters

lhSession
[in] Handle for the Simple MAPI session to be terminated. Session handles are returned by the MAPILogon function and invalidated by MAPILogoff. The value of the lhSession parameter must represent a valid session; it cannot be zero.
ulUIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If the ulUIParam parameter contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, ulUIParam is ignored.
flFlags
Reserved; must be zero.
ulReserved
Reserved; must be zero.

Return Values

MAPI_E_FAILURE
The flFlags parameter is invalid or one or more unspecified errors occurred.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed. The session was not terminated.
MAPI_E_INVALID_SESSION
An invalid session handle was used for the lhSession parameter. The session was not terminated.
SUCCESS_SUCCESS
The call succeeded and the session was terminated.

See Also

MAPILogon


MAPILogon

The MAPILogon function begins a Simple MAPI session, loading the default message store and address book providers.

Quick Info

Header file: MAPI.H

ULONG FAR PASCAL MAPILogon(
  ULONG ulUIParam,
  LPTSTR lpszProfileName,
  LPTSTR lpszPassword,
  FLAGS flFlags,
  ULONG ulReserved,
  LPLHANDLE lplhSession
)

Parameters

ulUIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If the ulUIParam parameter contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, ulUIParam is ignored.
lpszProfileName
[in] Pointer to a null-terminated profile name string, limited to 256 characters or less. This is the profile to use when logging on. If the lpszProfileName parameter is NULL or points to an empty string, and the flFlags parameter is set to MAPI_LOGON_UI, MAPILogon displays a logon dialog box with an empty name field.
lpszPassword
[in] Pointer to a null-terminated credential string, limited to 256 characters or less. If the messaging system does not require password credentials, or if it requires that the user enter them, the lpszPassword parameter should be NULL or point to an empty string. When the user must enter credentials, the flFlags parameter must be set to MAPI_LOGON_UI to allow a logon dialog box to be displayed.
flFlags
[in] Bitmask of option flags. The following flags can be set:
MAPI_FORCE_DOWNLOAD
An attempt should be made to download all of the user's messages before returning. If the MAPI_FORCE_DOWNLOAD flag is not set, messages can be downloaded in the background after the function call returns.
MAPI_NEW_SESSION
An attempt should be made to create a new session rather than acquire the environment's shared session. If the MAPI_NEW_SESSION flag is not set, MAPILogon uses an existing shared session.
MAPI_LOGON_UI
A logon dialog box should be displayed to prompt the user for logon information. If the user needs to provide a password and profile name to enable a successful logon, MAPI_LOGON_UI must be set.
MAPI_PASSWORD_UI
MAPILogon should only prompt for a password and not allow the user to change the profile name. Either MAPI_PASSWORD_UI or MAPI_LOGON_UI should not be set, since the intent is to select between two different dialog boxes for logon.
ulReserved
Reserved; must be zero.
lplhSession
[out] Simple MAPI session handle.

Return Values

MAPI_E_FAILURE
One or more unspecified errors occurred during logon. No session handle was returned.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed. No session handle was returned.
MAPI_E_LOGIN_FAILURE
There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No session handle was returned.
MAPI_E_TOO_MANY_SESSIONS
The user had too many sessions open simultaneously. No session handle was returned.
MAPI_E_USER_ABORT
The user canceled the logon dialog box. No session handle was returned.
SUCCESS_SUCCESS
The call succeeded and a Simple MAPI session was established.

Remarks

The MAPILogon function begins a session with the messaging system, returning a handle that can be used in subsequent MAPI calls to explicitly provide user credentials to the messaging system. To request the display of a logon dialog box if the credentials presented fail to validate the session, set the flFlags parameter to MAPI_LOGON_UI.

The client application tests for an existing session by calling MAPILogon with a NULL value for the lpszProfileName parameter, a NULL value for the lpszPassword parameter and by not setting the MAPI_LOGON_UI flag in flFlags. If there is an existing session, the call succeeds and returns a valid LHANDLE for the session. Otherwise, the call fails.

See Also

MAPILogoff


MAPIReadMail

The MAPIReadMail function retrieves a message for reading.

Quick Info

Header file: MAPI.H

ULONG FAR PASCAL MAPIReadMail(
  LHANDLE lhSession,
  ULONG ulUIParam,
  LPTSTR lpszMessageID,
  FLAGS flFlags,
  ULONG ulReserved,
  lpMapiMessage FAR * lppMessage
)

Parameters

lhSession
[in] Handle to a Simple MAPI session. The value of the lhSession parameter must represent a valid session; it cannot be zero.
ulUIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If the ulUIParam parameter contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, ulUIParam is ignored.
lpszMessageID
[in] Pointer to a message identifier string for the message to be read. The string is allocated by the caller.
flFlags
[in] Bitmask of option flags. The following flags can be set:
MAPI_BODY_AS_FILE
MAPIReadMail should write the message text to a temporary file and add it as the first attachment in the attachment list.
MAPI_ENVELOPE_ONLY
MAPIReadMail should read the message header only. File attachments are not copied to temporary files, and neither temporary file names nor message text is written. Setting this flag enhances performance.
MAPI_PEEK
MAPIReadMail does not mark the message as read. Marking a message as read affects its appearance in the user interface and generates a read receipt. If the messaging system does not support this flag, MAPIReadMail always marks the message as read. If MAPIReadMail encounters an error, it leaves the message unread.
MAPI_SUPPRESS_ATTACH
MAPIReadMail should not copy file attachments but should write message text into the MapiMessage structure. MAPIReadMail ignores this flag if the calling application has set the MAPI_ENVELOPE_ONLY flag. Setting the MAPI_SUPPRESS_ATTACH flag enhances performance.
ulReserved
Reserved; must be zero.
lppMessage
[out] Pointer to the location where the message is written. Messages are written to a MapiMessage structure which can be freed with a single call to the MAPIFreeBuffer function.

When MAPI_ENVELOPE_ONLY and MAPI_SUPPRESS_ATTACH are not set, attachments are written to temporary files pointed to by the lpFiles member of the MapiMessage structure. It is the caller's responsibility to delete these files when they are no longer needed.

Return Values

MAPI_E_ATTACHMENT_WRITE_FAILURE
An attachment could not be written to a temporary file. Check directory permissions.
MAPI_E_DISK_FULL
An attachment could not be written to a temporary file because there was not enough space on the disk.
MAPI_E_FAILURE
One or more unspecified errors occurred while reading the message.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to read the message.
MAPI_E_INVALID_MESSAGE
An invalid message identifier was passed in the lpszMessageID parameter.
MAPI_E_INVALID_SESSION
An invalid session handle was passed in the lhSession parameter. No message was retrieved.
MAPI_E_TOO_MANY_FILES
There were too many file attachments in the message. The message could not be read.
MAPI_E_TOO_MANY_RECIPIENTS
There were too many recipients of the message. The message could not be read.
SUCCESS_SUCCESS
The call succeeded and the message was read.

Remarks

The MAPIReadMail function returns one message, breaking the message content into the same parameters and structures used in the MAPISendMail function. MAPIReadMail fills a block of memory with the MapiMessage structure containing message elements, such as the subject, message class, delivery time, and the sender. File attachments are saved to temporary files, and the names are returned to the caller in the message structure. Recipients, attachments, and contents are copied from the message before MAPIReadMail returns to the caller, so later changes to the files do not affect the contents of the message.

A flag is provided to specify that only envelope information is to be returned from the call. Another flag (in the MapiMessage structure) specifies whether the message is marked as sent or unsent.

The caller is responsible for freeing the MapiMessage structure by calling the MAPIFreeBuffer function and deleting any files associated with attachments included with the message.

Before calling MAPIReadMail, use the MAPIFindNext function to verify that the message to be read is the one you want to be read. Because message identifiers are system-specific and opaque and can be invalidated at any time, MAPIReadMail considers a message identifier to be valid only for the current Simple MAPI session.

See Also

MAPIFreeBuffer, MAPILogon, MapiMessage


MAPIResolveName

The MAPIResolveName function transforms a message recipient's name as entered by a user to an unambiguous address list entry.

Quick Info

Header file: MAPI.H

ULONG FAR PASCAL MAPIResolveName(
  LHANDLE lhSession,
  ULONG ulUIParam,
  LPTSTR lpszName,
  FLAGS flFlags,
  ULONG ulReserved,
  lpMapiRecipDesc FAR * lppRecip
)

Parameters

lhSession
[in] Handle that represents a Simple MAPI session or zero. If the value of the lhSession parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. This temporary session can be an existing shared session or a new one. If necessary, the logon dialog box is displayed.
ulUIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If the ulUIParam parameter contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, ulUIParam is ignored.
lpszName
[in] Pointer to the name to be resolved.
flFlags
[in] Bitmask of option flags. The following flags can be set:
MAPI_AB_NOMODIFY
The caller is requesting that the dialog box be read-only, prohibiting changes. MAPIResolveName ignores this flag if MAPI_DIALOG is not set.
MAPI_DIALOG
A dialog box should be displayed for name resolution. If this flag is not set and the name cannot be resolved, MAPIResolveName returns the MAPI_E_AMBIGUOUS_RECIPIENT value.
MAPI_LOGON_UI
A dialog box should be displayed to prompt the user to log on if required. When the MAPI_LOGON_UI flag is not set, the client application does not display a logon dialog box and returns an error value if the user is not logged on.
MAPI_NEW_SESSION
An attempt should be made to create a new session rather than acquire the environment's shared session. If the MAPI_NEW_SESSION flag is not set, MAPIResolveName uses an existing shared session.
ulReserved
Reserved; must be zero.
lppRecip
[out] Pointer to a recipient structure if the resolution results in a single match. The recipient structure contains the resolved name and related information. Memory for this structure must be freed using the MAPIFreeBuffer function.

Return Values

MAPI_E_AMBIGUOUS_RECIPIENT
The recipient requested has not been or could not be resolved to a unique address list entry.
MAPI_E_UNKNOWN_RECIPIENT
The recipient could not be resolved to any address. The recipient might not exist or might be unknown.
MAPI_E_FAILURE
One or more unspecified errors occurred. The name was not resolved.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed. The name was not resolved.
MAPI_E_LOGIN_FAILURE
There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. The name was not resolved.
MAPI_E_NOT_SUPPORTED
The operation was not supported by the underlying messaging system.
MAPI_E_USER_ABORT
The user canceled one of the dialog boxes. The name was not resolved.
SUCCESS_SUCCESS
The call succeeded and the name was resolved.

Remarks

The MAPIResolveName function resolves a message recipient's name (as entered by a user) to an unambiguous address list entry, optionally prompting the user to choose between possible entries, if necessary. A recipient descriptor structure containing fully resolved information about the entry is allocated and returned. The caller should free this MAPIRecipDesc structure at some point by calling the MAPIFreeBuffer function. If MAPIResolveName returns an error value, it is not necessary to deallocate memory with MAPIFreeBuffer.

See Also

MAPIFreeBuffer, MAPILogon, MapiRecipDesc


MAPISaveMail

The MAPISaveMail function saves a message into the message store.

Quick Info

Header file: MAPI.H

ULONG FAR PASCAL MAPISaveMail(
  LHANDLE lhSession,
  ULONG ulUIParam,
  lpMapiMessage lpMessage,
  FLAGS flFlags,
  ULONG ulReserved,
  LPTSTR lpszMessageID
)

Parameters

lhSession
[in] Handle for a Simple MAPI session or zero. The value of the lhSession parameter must not be zero if the lpszMessageID parameter contains a valid message identifier. However, if lpszMessageID does not contain a valid message identifier, and the value of lhSession is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. This temporary session can be an existing shared session or a new one. If necessary, the logon dialog box is displayed.
ulUIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If the ulUIParam parameter contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, ulUIParam is ignored.
lpMessage
Input parameter pointing to a MapiMessage structure containing the contents of the message to be saved. The lpOriginator member is ignored. Applications can either ignore the flFlags member, or if the message has never been saved, can set the MAPI_SENT and MAPI_UNREAD flags.
flFlags
[in] Bitmask of option flags. The following flags can be set:
MAPI_LOGON_UI
A dialog box should be displayed to prompt the user to logon if required. When the MAPI_LOGON_UI flag is not set, the client application does not display a logon dialog box and returns an error value if the user is not logged on. MAPISaveMail ignores this flag if the lpszMessageID parameter is empty.
MAPI_LONG_MSGID
The returned message identifier is expected to be 512 characters. If this flag is set, the lpszMessageID parameter must be large enough to accomodate 512 characters.
MAPI_NEW_SESSION
An attempt should be made to create a new session rather than acquire the environment's shared session. If the MAPI_NEW_SESSION flag is not set, MAPISaveMail uses an existing shared session.
MAPI_LONG_MSGID
When the input message is NULL, this flag should be passed into MAPISaveMail, and the accompanying message identifier buffer should be 512 bytes long.
ulReserved
Reserved; must be zero.
lpszMessageID
[in, out] Pointer to either the message identifier to be replaced by the save operation or an empty string, indicating that a new message is to be created. The string must be allocated by the caller and must be able to hold at least 512 characters if the flFlags parameter is set to MAPI_LONG_MSGID. If the flFlags parameter is not set to MAPI_LONG_MSGID, the message identifier string can hold 64 characters.

Return Values

MAPI_E_ATTACHMENT_NOT_FOUND
An attachment could not be located at the specified path. Either the drive letter was invalid, the path was not found on that drive, or the file was not found in that path.
MAPI_E_BAD_RECIPTYPE
The recipient type in the lpMessage was invalid.
MAPI_E_FAILURE
One or more unspecified errors occurred while saving the message. No message was saved.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to save the message. No message was saved.
MAPI_E_INVALID_MESSAGE
An invalid message identifier was passed in the lpszMessageID parameter; no message was saved.
MAPI_E_INVALID_RECIPS
One or more recipients of the message were invalid or could not be identified.
MAPI_E_INVALID_SESSION
An invalid session handle was passed in the lhSession parameter. No message was saved.
MAPI_E_LOGIN_FAILURE
There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No message was saved.
MAPI_E_NOT_SUPPORTED
The operation was not supported by the underlying messaging system.
MAPI_E_USER_ABORT
The user canceled one of the dialog boxes. No message was saved.
SUCCESS_SUCCESS
The call succeeded and the message was saved.

Remarks

The MAPISaveMail function saves a message, optionally replacing an existing message. Before calling MAPISaveMail, use the MAPIFindNext function to verify that the message to be saved is the one you want saved. The elements of the message identified by the lpszMessageID parameter are replaced by the elements in the lpMessage parameter. If lpszMessageID is empty, a new message is created. All replaced messages are saved in their appropriate folders. New messages are saved in the folder appropriate for incoming messages of that class.

Not all messaging systems support storing messages. If the underlying messaging system does not support message storage, MAPISaveMail returns the MAPI_E_NOT_SUPPORTED value.

Because message identifiers are system-specific and opaque and can be invalidated at any time, MAPISaveMail considers a message identifier to be valid only for the current Simple MAPI session. MAPISaveMail handles invalid message identifiers by returning the MAPI_E_INVALID_MESSAGE value.

See Also

MAPILogon, MapiMessage


MAPISendDocuments

The MAPISendDocuments function sends a standard message with one or more attached files and a cover note. The cover note is a dialog box that allows the user to enter a list of recipients and an optional message. MAPISendDocuments differs from the MAPISendMail function in that it allows less flexibility in message generation.

Quick Info

Header file: MAPI.H

ULONG FAR PASCAL MAPISendDocuments(
  ULONG ulUIParam,
  LPTSTR lpszDelimChar,
  LPTSTR lpszFullPaths,
  LPTSTR lpszFileNames,
  ULONG ulReserved
)

Parameters

ulUIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If the ulUIParam parameter contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, ulUIParam is ignored.
lpszDelimChar
[in] Pointer to a character that the caller uses to delimit the names pointed to by the lpszFullPaths and lpszFileNames parameters. The caller should select a character for the delimiter that is not used in operating system filenames.
lpszFullPaths
[in] Pointer to a string containing a list of full paths (including drive letters) to attachment files. This list is formed by concatenating correctly formed file paths separated by the character specified in the lpszDelimChar parameter and followed by a null terminator. An example of a valid list is:
C:\TMP\TEMP1.DOC;C:\TMP\TEMP2.DOC

The files specified in this parameter are added to the message as file attachments. If this parameter is NULL or contains an empty string, the Send Note dialog box is displayed with no attached files.

lpszFileNames
[in] Pointer to a null-terminated list of the original filenames as they should appear in the message. When multiple names are specified, the list is formed by concatenating the filenames separated by the character specified in the lpszDelimChar parameter and followed by a null terminator. An example is:
TEMP3.DOC;TEMP4.DOC

If there is no value for the lpszFileNames parameter or if it is empty, MAPISendDocuments sets the filenames set to the filename values indicated by the lpszFullPaths parameter.

ulReserved
Reserved; must be zero.

Return Values

MAPI_E_ATTACHMENT_OPEN_FAILURE
One or more files in the lpszFilePaths parameter could not be located. No message was sent.
MAPI_E_ATTACHMENT_WRITE_FAILURE
An attachment could not be written to a temporary file. Check directory permissions.
MAPI_E_FAILURE
One or more unspecified errors occurred while sending the message. It is not known if the message was sent.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed.
MAPI_E_LOGIN_FAILURE
There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No message was sent.
MAPI_E_USER_ABORT
The user canceled one of the dialog boxes. No message was sent.
SUCCESS_SUCCESS
The call succeeded and the message was sent.

Remarks

The MAPISendDocuments function sends a standard message, always displaying a cover note dialog box so the user can provide recipients and other sending options. This function tries to establish a session using the messaging system's shared session. If no shared session exists, it prompts the user for logon information to establish a session. Before MAPISendDocuments returns, it ends the session.

Message attachments can include the active document or all the currently open documents in the client application that called MAPISendDocuments. This function is used primarily for calls from a macro or scripting language, often found in applications such as spreadsheet or word-processing programs.

MAPISendDocuments creates as many file attachments as there are paths specified by the lpszFullPaths parameter in spite of the fact that there can be different numbers of paths and filenames. The caller is responsible for deleting temporary files created when using MAPISendDocuments.

See Also

MAPISendMail


MAPISendMail

The MAPISendMail function sends a message. This function differs from the MAPISendDocuments function in that it allows greater flexibility in message generation.

Quick Info

Header file: MAPI.H

ULONG FAR PASCAL MAPISendMail(
  LHANDLE lhSession,
  ULONG ulUIParam,
  lpMapiMessage lpMessage,
  FLAGS flFlags,
  ULONG ulReserved
)

Parameters

lhSession
[in] Handle to a Simple MAPI session or zero. If the value of the lhSession parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. This temporary session can be an existing shared session or a new one. If necessary, the logon dialog box is displayed.
ulUIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If the ulUIParam parameter contains a parent window handle, it is of type HWND (cast to a ULONG). If no dialog box is displayed during the call, ulUIParam is ignored.
lpMessage
[in] Pointer to a MapiMessage structure containing the message to be sent. If the MAPI_DIALOG flag is not set, the nRecipCount and lpRecips members must be valid for successful message delivery. Client applications can set the flFlags member to MAPI_RECEIPT_REQUESTED to request a read report. All other members are ignored and unused pointers should be NULL.
flFlags
[in] Bitmask of option flags. The following flags can be set:
MAPI_DIALOG
A dialog box should be displayed to prompt the user for recipients and other sending options. When MAPI_DIALOG is not set, at least one recipient must be specified.
MAPI_LOGON_UI
A dialog box should be displayed to prompt the user to log on if required. When the MAPI_LOGON_UI flag is not set, the client application does not display a logon dialog box and returns an error value if the user is not logged on. MAPISendMail ignores this flag if the lpszMessageID parameter is empty.
MAPI_NEW_SESSION
An attempt should be made to create a new session rather than acquire the environment's shared session. If the MAPI_NEW_SESSION flag is not set, MAPISendMail uses an existing shared session.
ulReserved
Reserved; must be zero.

Return Values

MAPI_E_AMBIGUOUS_RECIPIENT
A recipient matched more than one of the recipient descriptor structures and MAPI_DIALOG was not set. No message was sent.
MAPI_E_ATTACHMENT_NOT_FOUND
The specified attachment was not found. No message was sent.
MAPI_E_ATTACHMENT_OPEN_FAILURE
The specified attachment could not be opened. No message was sent.
MAPI_E_BAD_RECIPTYPE
The type of a recipient was not MAPI_TO, MAPI_CC, or MAPI_BCC. No message was sent.
MAPI_E_FAILURE
One or more unspecified errors occurred. No message was sent.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed. No message was sent.
MAPI_E_INVALID_RECIPS
One or more recipients were invalid or did not resolve to any address.
MAPI_E_LOGIN_FAILURE
There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No message was sent.
MAPI_E_TEXT_TOO_LARGE
The text in the message was too large. No message was sent.
MAPI_E_TOO_MANY_FILES
There were too many file attachments. No message was sent.
MAPI_E_TOO_MANY_RECIPIENTS
There were too many recipients. No message was sent.
MAPI_E_UNKNOWN_RECIPIENT
A recipient did not appear in the address list. No message was sent.
MAPI_E_USER_ABORT
The user canceled one of the dialog boxes. No message was sent.
SUCCESS_SUCCESS
The call succeeded and the message was sent.

Remarks

The MAPISendMail function sends a standard message, with or without any user interaction. The profile must be configured so that MAPISendMail can open the default service providers without requiring user interaction. However, if the flFlags parameter is set to MAPI_NEW_SESSION, disallowing the use of a shared session, and the profile requires a password, MAPI_LOGON_UI must be set or the function will fail. Client applications can avoid this situation by using an explicit profile without a password or by using the default profile without a password.

Client applications can provide a full or partial list of recipient names, subject text, file attachments, or message text. If any information is missing, MAPISendMail can prompt the user for it. If no information is missing, either the message can be sent as is or the user can be prompted to verify the information, changing values if necessary.

A successful return from MAPISendMail does not necessarily imply recipient validation. The message might not have been sent to all recipients. Depending on the transport provider, recipient validation can be a lengthy process.

A NULL value for the lpszSubject member of the MapiMessage structure pointed to by the lpMessage parameter indicates that there is no text for the subject of the message. A NULL value for the lpszNoteText member indicates that there is no message text. Some client applications can truncate subject lines that are too long or contain carriage returns, line feeds, or form feeds.

Each paragraph should be terminated with a CR (0x0d), an LF (0x0a), or a CRLF pair (0x0d0a). MAPISendMail wraps lines as appropriate. If the text exceeds system limits, the function returns the MAPI_E_TEXT_TOO_LARGE value.

The lpszMessageType member of the MapiMessage structure pointed to by lpMessage is used only by non-IPM applications. Applications that handle IPM messages can set it to NULL or have it point to an empty string.

The number of attachments per message can be limited in some messaging systems. If the limit is exceeded, the MAPI_E_TOO_MANY_FILES value is returned. If no files are specified, a pointer value of NULL should be assigned to the lpFiles member of the structure pointed to by lpMessage. File attachments are copied to the message before MAPISendMail returns; therefore, later changes to the files do not affect the contents of the message. The files must be closed when they are copied. Do not attempt to display attachments outside the range of the message text.

Some messaging systems can limit the number of recipients per message. A pointer value of NULL for the lpRecips member in the MapiMessage structure pointed to by lpMessage indicates no recipients. If the client application passes a non-NULL value indicating a number of recipients exceeding the system limit, MAPISendMail returns the MAPI_E_TOO_MANY_RECIPIENTS value. If the value of the nRecipCount member in the MapiMessage structure pointed to by lpMessage is 0, the MAPI_DIALOG flag must be present in the call to MAPISendMail.

Note that the lpRecips member in the MapiMessage structure can include either an entry identifier, the recipient's name, an address, or a name and address pair. The following table shows how MAPISendMail handles the variety of information that can be specified:

Information | Action
entry identifier | No name resolution; the name and address are ignored.
name | Name resolved using the Simple MAPI resolution rules.
address | No name resolution; address is used for both message delivery and for displaying the recipient name.
name and address | No name resolution; name used only for displaying the recipient name.

Client applications that send messages to custom recipients can avoid name resolution. Such clients should set the lpszAddress member of the MapiRecipDesc structure pointed to by the lpRecips member of the MapiMessage structure pointed to by the lpMessage parameter to the custom address.

MAPISendMail does not require an originator-type recipient to send a message.

See Also

MAPILogon, MapiMessage, MapiRecipDesc


Structures for C and C++

The following alphabetized entries contain documentation for the Simple MAPI structures for C and C++.


MapiFileDesc (Simple MAPI)

A MapiFileDesc structure contains information about a file containing a message attachment stored as a temporary file. That file can contain a static OLE object, an embedded OLE object, an embedded message, and other types of files.

Quick Info

Header file: MAPI.H

typedef struct {
     ULONG ulReserved;
     ULONG flFlags;
     ULONG nPosition;
     LPTSTR lpszPathName;
     LPTSTR lpszFileName;
     LPVOID lpFileType;
} MapiFileDesc, FAR *lpMapiFileDesc;

Members

ulReserved
Reserved; must be zero.
flFlags
Bitmask of attachment flags. The following flags can be set:
MAPI_OLE
The attachment is an OLE object. If MAPI_OLE_STATIC is also set, the attachment is a static OLE object. If MAPI_OLE_STATIC is not set, the attachment is an embedded OLE object.
MAPI_OLE_STATIC
The attachment is a static OLE object.

If neither flag is set, the attachment is treated as a data file.

nPosition
An integer used to indicate where in the message text to render the attachment. Attachments replace the character found at a certain position in the message text. That is, attachments replace the character in the MapiMessage structure field NoteText[nPosition]. A value of – 1 (0xFFFFFFFF) means the attachment position is not indicated; the client application will have to provide a way for the user to access the attachment.
lpszPathName
Pointer to the fully qualified path of the attached file. This path should include the disk drive letter and directory name.
lpszFileName
Pointer to the attachment filename seen by the recipient, which may differ from the filename in the lpszPathName member if temporary files are being used. If the lpszFileName member is empty or NULL, the filename from lpszPathName is used.
lpFileType
Pointer to the attachment file type, which can be represented with a MapiFileTagExt structure. A value of NULL indicates an unknown file type or a file type determined by the operating system.

Remarks

Simple MAPI works with three kinds of embedded attachments:

  • Data file attachments
  • Editable OLE object file attachments
  • Static OLE object file attachments

Data file attachments are simply data files. OLE object file attachments are OLE objects that are displayed in the message text. If the OLE attachment is editable, the recipient can double-click it and its source application will be started to handle the edit session. If the OLE attachment is static, the object cannot be edited. The flag set in the flFlags member of the MapiFileDesc structure determines the kind of a particular attachment. Embedded messages can be identified by a .MSG extension in the lpszFileName member.

OLE object files are file representations of OLE object streams. The client application can recreate an OLE object from the file by calling the OLE function OleLoadFromStream with an OLESTREAM object that reads the file contents. If an OLE file attachment is included in an outbound message, the OLE object stream should be written directly to the file used as the attachment.

When using the MapiFileDesc member nPosition, the client application should not place two attachments in the same location. Client applications might not display file attachments at positions beyond the end of the message text.

See Also

MapiFileTagExt


MapiFileTagExt (Simple MAPI)

A MapiFileTagExt structure specifies a message attachment's type at its creation and its current form of encoding so that it can be restored to its original type at its destination.

Quick Info

Header file: MAPI.H

typedef struct {
     ULONG ulReserved;
     ULONG cbTag;
     LPBYTE lpTag;
     ULONG cbEncoding;
     LPBYTE lpEncoding
} MapiFileTagExt, FAR *lpMapiFileTagExt;

Members

ulReserved
Reserved; must be zero.
cbTag
The size, in bytes, of the value defined by the lpTag member.
lpTag
Pointer to an X.400 object identifier indicating the type of the attachment in its original form, for example "Microsoft Excel worksheet".
cbEncoding
The size, in bytes, of the value defined by the lpEncoding member.
lpEncoding
Pointer to an X.400 object identifier indicating the form in which the attachment is currently encoded, for example MacBinary, UUENCODE, or binary.

Remarks

A MapiFileTagExt structure defines the type of an attached file for purposes such as encoding and decoding the file, choosing the correct application to launch when opening it, or any use that requires full information regarding the file type. Client applications can use information in the lpTag and lpEncoding members of this structure to determine what to do with an attachment.

See Also

PR_ATTACH_TAG, PR_ATTACH_ENCODING, MapiFileDesc


MapiMessage (Simple MAPI)

A MapiMessage structure contains information about a message.

Quick Info

Header file: MAPI.H

typedef struct {
     ULONG ulReserved;
     LPTSTR lpszSubject;
     LPTSTR lpszNoteText;
     LPTSTR lpszMessageType;
     LPTSTR lpszDateReceived;
     LPTSTR lpszConversationID;
     FLAGS flFlags;
     lpMapiRecipDesc lpOriginator;
     ULONG nRecipCount;
     lpMapiRecipDesc lpRecips;
     ULONG nFileCount;
     lpMapiFileDesc lpFiles;
} MapiMessage, FAR *lpMapiMessage;

Members

ulReserved
Reserved; must be zero.
lpszSubject
Pointer to the text string describing the message subject, typically limited to 256 characters or less. If this member is empty or NULL, the user has not entered subject text.
lpszNoteText
Pointer to a string containing the message text. If this member is empty or NULL, there is no message text.
lpszMessageType
Pointer to a string indicating a non-IPM type of message. Client applications can select message types for their non-IPM messages. Clients that only support IPM messages can ignore the lpszMessageType member when reading messages and set it to empty or NULL when sending messages.
lpszDateReceived
Pointer to a string indicating the date when the message was received. The format is YYYY/MM/DD HH:MM, using a 24-hour clock.
lpszConversationID
Pointer to a string identifying the conversation thread to which the message belongs. Some messaging systems can ignore and not return this member.
flFlags
Bitmask of message status flags. The following flags can be set:
MAPI_RECEIPT_REQUESTED
A receipt notification is requested. Client applications set this flag when sending a message.
MAPI_SENT
The message has been sent.
MAPI_UNREAD
The message has not been read.
lpOriginator
Pointer to a MapiRecipDesc structure containing information about the sender of the message.
nRecipCount
The number of message recipient structures in the array pointed to by the lpRecips member. A value of zero indicates no recipients are included.
lpRecips
Pointer to an array of MapiRecipDesc structures, each containing information about a message recipient.
nFileCount
The number of structures describing file attachments in the array pointed to by the lpFiles member. A value of zero indicates no file attachments are included.
lpFiles
Pointer to an array of MapiFileDesc structures, each containing information about a file attachment.

See Also

MapiFileDesc, MapiRecipDesc


MapiRecipDesc (Simple MAPI)

A MapiRecipDesc structure contains information about a message sender or recipient.

Quick Info

Header file: MAPI.H

typedef struct {
     ULONG ulReserved
     ULONG ulRecipClass;
     LPTSTR lpszName;
     LPTSTR lpszAddress;
     ULONG ulEIDSize;
     LPVOID lpEntryID;
} MapiRecipDesc, FAR *lpMapiRecipDesc;

Members

ulReserved
Reserved; must be zero.
ulRecipClass
Contains a numeric value that indicates the type of recipient. Possible values are:
Value | Constant | Meaning
0 | MAPI_ORIG | Indicates the original sender of the message.
1 | MAPI_TO | Indicates a primary message recipient.
2 | MAPI_CC | Indicates a recipient of a message copy.
3 | MAPI_BCC | Indicates a recipient of a blind copy.

lpszName
Pointer to the display name of the message recipient or sender.
lpszAddress
Optional pointer to the recipient or sender's address; this address is provider-specific message delivery data. Generally, the messaging system provides such addresses for inbound messages. For outbound messages, the lpszAddress member can point to an address entered by the user for a recipient not in an address book (that is, a custom recipient).

The format of an address pointed to by the lpszAddress member is [address type][e-mail address]. Examples of valid addresses are FAX:206-555-1212 and SMTP:M@X.COM.

ulEIDSize
The size, in bytes, of the entry identifier pointed to by the lpEntryID member.
lpEntryID
Pointer to an opaque entry identifier used by a messaging system service provider to identify the message recipient. Entry identifiers have meaning only for the service provider; client applications will not be able to decipher them. The messaging system uses this member to return valid entry identifiers for all recipients or senders listed in the address book.


Functions for Visual Basic

Visual Basic uses a different set of calling and programming conventions than C and C++ use. Different structure and parameter definitions support the Visual Basic representation of strings and of structures, which in Visual Basic are called types. The following list describes how programming Simple MAPI Visual Basic applications differs from programming Simple MAPI C and C++ applications:

  • Because the concept of a pointer is foreign to Visual Basic, developers use extra function parameters instead of the complex pointer structures used in C and C++.
  • Because the Visual Basic MAPI functions are declared, it is not necessary to explicitly cast passed arguments using ByVal.
  • An empty string in a string variable is equivalent to a NULL value.
  • Arrays must be dynamically declared so that they are redimensioned when the Simple MAPI function is executed.
  • Visual Basic manages memory, eliminating the need for calling the MAPIFreeBuffer function.
  • All structures used in the Visual Basic version of Simple MAPI are Visual Basic types rather than C-language structures.
  • All strings used in the Visual Basic version of Simple MAPI are Visual Basic strings rather than C-language strings.

The Simple MAPI functions for Visual Basic work with Visual Basic 3, Visual Basic 4, and Visual Basic for Applications. Note that slight differences in the 16-bit and 32-bit Visual Basic runtime DLLs mean that some Simple MAPI functions have different declarations depending on which runtime is being used. The 32-bit declarations use explicit Visual Basic array notation. The alternate declarations are documented with the functions that have them.


MAPIAddress (VB)

The Visual Basic MAPIAddress function enables users to create or modify a set of recipients. MAPIAddress generates an address-book dialog box that shows the contents of the recipient set and allows the user to select new entries or change existing entries.

Quick Info

Header file: MAPIVB32.BAS

MAPIAddress(

Session as Long,
UIParam as Long,
Caption as String,
EditFields as Long,
Label as String,
RecipCount as Long,
Recipients() as MapiRecip,
Flags as Long,
Reserved as Long) as Long

Parameters

Session
[in] Session handle that represents a Simple MAPI session or zero. If the value of the Session parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. This temporary session can be an existing shared session or a new one. If necessary, a logon dialog box is displayed.
UIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.
Caption
[in] Caption of the address-list dialog box. If this parameter is an empty string, the default value "Address Book" is used.
EditFields
[in] The number of edit controls that should be present in the address list. The values 0 through 4are valid. If the value of the nEditFields parameter is 4, each recipient class supported by the underlying messaging system has an edit control. If the value of EditFields is zero, only address list browsing is possible. Values of 1, 2, or 3 control the number of edit controls present.

However, if the number of recipient classes in the Recipients parameter is greater than the value of EditFields, the number of classes in Recipients is used to indicate the number of edit controls instead of the value of EditFields. If the value of EditFields is 1 and more than one kind of entry exists in Recipients, then the Labels parameter is ignored.

Entries selected for the different controls are differentiated by the ulRecipClass member in the returned recipient structure.

Label
[in] Edit control label in the address-list dialog box. The Label parameter is ignored and should be an empty string except when the value of the EditFields parameter is 1. If you want a default control label "To:", Label should be an empty string.
RecipCount
[in] The number of entries in the Recipients parameter. If the value of the RecipCount parameter is zero, Recipients is ignored.
Recipients
[in] The initial array of recipient entries to be used to populate edit controls in the address-list dialog box. Recipient entries need not be grouped by recipient class. If the value of the greatest recipient class present is greater than the value of the EditFields parameter, the EditFields and Label parameters are ignored. This array is redimensioned as necessary to accommodate the entries made by the user in the address-list dialog box.
Flags
[in] Bitmask of flags. The following flags can be set:
MAPI_LOGON_UI
A dialog box should be displayed to prompt the user to log on if required. When the MAPI_LOGON_UI flag is not set, the client application does not display a logon dialog box and returns an error value if the user is not logged on.
MAPI_NEW_SESSION
An attempt should be made to create a new session rather than acquire the environment's shared session. If the MAPI_NEW_SESSION flag is not set, MAPIAddress uses an existing shared session.
Reserved
Reserved; must be zero.

Return Values

MAPI_E_FAILURE
One or more unspecified errors occurred while building recipient lists or browsing the address book. No list of recipients was returned.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed. No list of recipients was returned.
MAPI_E_INVALID_EDITFIELDS
The value of the nEditFields parameter was outside the range of 0 through 4. No list of recipients was returned.
MAPI_E_INVALID_RECIPS
One or more of the recipients in the address list was not valid or the Recipients parameter was not a valid array. No list of recipients was returned.
MAPI_E_INVALID_SESSION
An invalid session handle was used for the lhSession parameter. No list of recipients was returned.
MAPI_E_LOGIN_FAILURE
There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No list of recipients was returned.
MAPI_E_NOT_SUPPORTED
The operation was not supported by the underlying messaging system. A list of recipients might have been returned.
MAPI_E_USER_ABORT
The user canceled one of the dialog boxes. No list of recipients was returned.
SUCCESS_SUCCESS
The call succeeded and a list of address entries was returned.

Remarks

The MAPIAddress function makes it possible for users to create or modify a set of address-list entries using a standard address-list dialog box. The dialog box cannot be suppressed, but function parameters allow the caller to set characteristics of the dialog box.

The call is made with an initial, and possibly empty, set of recipients. The address-list dialog box shows the contents of the recipient set; users can choose new entries to add to the set. The final set of recipients is returned to the caller in the RecipCount and Recipients parameters, destroying their initial values.

The declaration of this function for the 32-bit Visual Basic runtime is:

MAPIAddress(

Session As Long,
UIParam As Long,
Caption As String,
nEditFields As Long,
Label As String,
nRecipients As Long,
Recips() As MapiRecip,
Flags As Long,
Reserved As Long) As Long


MAPIDeleteMail (VB)

The Visual Basic MAPIDeleteMail function deletes a message.

Quick Info

Header file: MAPIVB32.BAS

MAPIDeleteMail(

Session as Long,
UIParam as Long,
MessageID as String,
Flags as Long,
Reserved as Long) as Long

Parameters

Session
[in] Session handle that represents a valid Simple MAPI session. The value of the Session parameter cannot be zero.
UIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.
MessageID
[in] Identifier for the message to be deleted. This string identifier is messaging system-specific and will be invalid when the MAPIDeleteMail function successfully returns. Both the MAPIFindNext and MAPISaveMail functions return message identifiers.
Flags
Reserved; must be zero.
Reserved
Reserved; must be zero.

Return Values

MAPI_E_FAILURE
One or more unspecified errors occurred while deleting the message. No message was deleted.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed. No message was deleted.
MAPI_E_INVALID_MESSAGE
An invalid message identifier was passed in for the MessageID parameter. No message was deleted.
MAPI_E_INVALID_SESSION
An invalid session handle was passed in for the Session parameter. No message was deleted.
SUCCESS_SUCCESS
The call succeeded and the message was deleted.

Remarks

To find the message to be deleted, call the MAPIFindNext function before calling MAPIDeleteMail.

The declaration of this function for the 32-bit Visual Basic runtime is:

MAPIDeleteMail(

ByVal Session&,
ByVal UIParam&,
ByVal MsgID$,
ByVal Flags&,
ByVal Reserved&) As Long


MAPIDetails (VB)

The Visual Basic MAPIDetails function displays a dialog box containing the details of a selected address-list entry.

Quick Info

Header file: MAPIVB32.BAS

MAPIDetails(

Session as Long,
UIParam as Long,
Recipient as MapiRecip,
Flags as Long,
Reserved as Long) as Long

Parameters

Session
[in] Session handle that represents a Simple MAPI session or zero. If the value of the Session parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. This temporary session can be an existing shared session or a new one. If necessary, a logon dialog box is displayed.
UIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.
Recipient
[in] Recipient descriptor containing the entry whose details are to be displayed. MAPIDetails ignores all members of the MapiRecip type except EIDSize and EntryID. If the value of the EIDSize member is non-zero, MAPIDetails resolves the recipient entry. If the value of EIDSize is zero, the MAPI_E_AMBIGUOUS_RECIPIENT value is returned.
Flags
[in] Bitmask of flags. The following flags can be set:
MAPI_AB_NOMODIFY
The caller is requesting that the dialog box be read-only, prohibiting changes. MAPIDetails might or might not honor the request.
MAPI_LOGON_UI
A dialog box should be displayed to prompt the user to log on if required. When the MAPI_LOGON_UI flag is not set, the client application does not display a logon dialog box and returns an error value if the user is not logged on.
MAPI_NEW_SESSION
An attempt should be made to create a new session rather than acquire the environment's shared session. If the MAPI_NEW_SESSION flag is not set, MAPIDetails uses an existing shared session.
Reserved
Reserved; must be zero.

Return Values

MAPI_E_AMBIGUOUS_RECIPIENT
The recipient requested has not been or could not be resolved to a unique address list entry.
MAPI_E_FAILURE
One or more unspecified errors occurred. No dialog box was displayed.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed. No dialog box was displayed.
MAPI_E_INVALID_RECIPS
The recipient specified in the Recipient parameter was unknown. No dialog box was displayed.
MAPI_E_LOGIN_FAILURE
There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No dialog box was displayed.
MAPI_E_NOT_SUPPORTED
The operation was not supported by the underlying messaging system.
MAPI_E_USER_ABORT
The user canceled either the logon dialog box or the details dialog box.
SUCCESS_SUCCESS
The call succeeded and the details dialog box was displayed.

Remarks

The MAPIDetails function presents a dialog box that shows the details of a particular address list entry. The display name and address are the minimum attributes that are displayed in the dialog box; more information can be shown depending on the directory to which the entry belongs. The details dialog box cannot be suppressed, but the caller can request that it be read-only or modifiable.

Details can only be shown for resolved address list entries. An entry is resolved if the EIDSize member of the MapiRecip type is nonzero. Entries are resolved when they are returned by the MAPIAddress or MAPIResolveName functions and as the result of being recipients of read mail.

The declaration of this function for the 32-bit Visual Basic runtime is:

MAPIDetails(

ByVal Session&,
ByVal UIParam&,
Recipient As MapiRecip,
ByVal Flags&,
ByVal Reserved&) As Long


MAPIFindNext (VB)

The Visual Basic MAPIFindNext function retrieves the next (or first) message identifier of a specified type of incoming message.

Quick Info

Header file: MAPIVB32.BAS

MAPIFindNext(

Session as Long,
UIParam as Long,
MessageType as String,
SeedMessageID as String,
Flags as Long,
Reserved as Long,
MessageID as String) as Long

Parameters

Session
[in] Session handle that represents a Simple MAPI session. The value of the Session parameter must represent a valid session; it cannot be zero.
UIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.
MessageType
[in] The type of message to search. To find an interpersonal message (IPM), use an empty string, "".
SeedMessageID
[in] The message identifier seed for the request. If the SeedMessageID parameter is an empty string, MAPIFindNext retrieves the first message that matches the type specified in the MessageType parameter.
Flags
[in] Bitmask of option flags. The following flags can be set:
MAPI_GUARANTEE_FIFO
The message identifiers returned should be in the order of time received. MAPIFindNext calls can take longer if this flag is set. Some implementations cannot honor this request and return the MAPI_E_NO_SUPPORT value.
MAPI_NEW_SESSION
An attempt should be made to create a new session rather than acquire the environment's shared session. If the MAPI_NEW_SESSION flag is not set, MAPIFindNext uses an existing shared session.
MAPI_UNREAD_ONLY
Only unread messages of the specified type should be enumerated. When this flag is not set, MAPIFindNext can return any message of the specified type.
Reserved
Reserved; must be zero.
MessageID
[out] The returned message identifier. The MessageID parameter is a variable-length string allocated by the caller. To ensure compatibility, allocate 512 characters. A smaller buffer is sufficient only if the returned message identifier is always 64 characters or less.

Return Values

MAPI_E_FAILURE
One or more unspecified errors occurred while matching the message type. The call failed before message type matching could take place.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed. No message was found.
MAPI_E_INVALID_MESSAGE
An invalid message identifier was passed in the SeedMessageID parameter. No message was found.
MAPI_E_INVALID_SESSION
An invalid session handle was passed in the lhSession parameter. No message was found.
MAPI_E_NO_MESSAGES
A matching message could not be found.
SUCCESS_SUCCESS
The call succeeded and the message identifier was returned.

Remarks

The MAPIFindNext function allows a client application to enumerate messages of a given type. This function can be called repeatedly to list all messages in the folder. Message identifiers returned from MAPIFindNext can be used in other Simple MAPI calls to retrieve message contents and delete messages. This function is for processing incoming messages, not for managing received messages.

When the value of the SeedMessageID parameter is NULL or empty, MAPIFindNext returns the message identifier for the first message of the type specified by the MessageType parameter. When SeedMessageID contains a valid identifier, MAPIFindNext returns the next matching message of the type specified by MessageType. Repeated calls to MAPIFindNext ultimately result in a return of the MAPI_E_NO_MESSAGES value, which means the enumeration is complete.

Because message identifiers are messaging system-specific and can be invalidated at any time, message identifiers are valid only for the current session. If the message identifier passed in with SeedMessageID is invalid, MAPIFindNext returns the MAPI_E_INVALID_MESSAGE value.

Message type matching is done against message class strings. All message types whose names match, up to the length specified in MessageType, are returned.

The declaration of this function for the 32-bit Visual Basic runtime is:

MAPIFindNext(

ByVal Session&,
ByVal UIParam&,
MsgType$,
SeedMsgID$,
ByVal Flag&,
ByVal Reserved&,
MsgID$) As Long


MAPILogoff (VB)

The Visual Basic MAPILogoff function ends a session with the messaging system.

Quick Info

Header file: MAPIVB32.BAS

MAPILogoff(

Session as Long,
UIParam as Long,
Flags as Long,
Reserved as Long) as Long

Parameters

Session
[in] Handle for a Simple MAPI session to be terminated. Session handles are returned by MAPILogon and invalidated by MAPILogoff. The value of the Session parameter must represent a valid session; it cannot be zero.
UIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.
Flags
Reserved; must be zero.
Reserved
Reserved; must be zero.

Return Values

MAPI_E_FAILURE
One or more unspecified errors occurred.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed. The session was not terminated.
MAPI_E_INVALID_SESSION
An invalid session handle was used for the Session parameter. The session was not terminated.
SUCCESS_SUCCESS
The call succeeded and the session was terminated.

The declaration of this function for the 32-bit Visual Basic runtime is:

MAPILogoff(

ByVal Session&,
ByVal UIParam&,
ByVal Flags&,
ByVal Reserved&) As Long


MAPILogon (VB)

The Visual Basic MAPILogon function begins a Simple MAPI session, loading the default message store and address book providers.

Quick Info

Header file: MAPIVB32.BAS

MAPILogon(

UIParam ByVal as Long,
User as String,
Password as String,
Flags as Long,
Reserved as Long,
Session as Long) as Long

Parameters

UIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.
User
[in] Client account-name string, limited to 256 characters or less. This is the name to use when logging on. If the User parameter is empty, and the Flags parameter is set to MAPI_LOGON_UI, MAPILogon displays a logon dialog box with an empty name field.
Password
[in] Credential string, limited to 256 characters or less. If the messaging system does not require password credentials, or if it requires that the user enter them, the Password parameter should be empty. When the user must enter credentials, the Flags parameter must be set to MAPI_LOGON_UI to allow a logon dialog box to be displayed.
Flags
[in] Bitmask of option flags. The following flags can be set:
MAPI_FORCE_DOWNLOAD
An attempt should be made to download all of the user's messages before returning. If the MAPI_FORCE_DOWNLOAD flag is not set, messages can be downloaded in the background after the function call returns.
MAPI_LOGON_UI
A logon dialog box should be displayed to prompt the user for logon information. If the user needs to provide information to enable a successful logon, MAPI_LOGON_UI must be set.
MAPI_NEW_SESSION
An attempt should be made to create a new session rather than acquire the environment's shared session. If the MAPI_NEW_SESSION flag is not set, MAPILogon uses an existing shared session.
Reserved
Reserved; must be zero.
Session
[out] Simple MAPI session handle.

Return Values

MAPI_E_FAILURE
One or more unspecified errors occurred during logon. No session handle was returned.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed. No session handle was returned.
MAPI_E_LOGIN_FAILURE
There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No session handle was returned.
MAPI_E_TOO_MANY_SESSIONS
The user had too many sessions open simultaneously. No session handle was returned.
MAPI_E_USER_ABORT
The user canceled the process. No session handle was returned.
SUCCESS_SUCCESS
The call succeeded and a session was established.

Remarks

The MAPILogon function begins a session with the messaging system, returning a handle that can be used in subsequent MAPI calls to explicitly provide user credentials to the messaging system. To request the display of a logon dialog box if the credentials presented fail to validate the session, set the Flags parameter to MAPI_LOGON_UI.

The declaration of this function for the 32-bit Visual Basic runtime is:

MAPILogon(

ByVal UIParam&,
ByVal User$,
ByVal Password$,
ByVal Flags&,
ByVal Reserved&,
Session&) As Long


MAPIReadMail (VB)

The Visual Basic MAPIReadMail function retrieves a message for reading.

Quick Info

Header file: MAPIVB32.BAS

MAPIReadMail(

Session as Long,
 UIParam as Long,
MessageID as String,
Flags as Long,
Reserved as Long,
Message as MapiMessage,
Originator as MapiRecip,
Recips() as MapiRecip,
Files() as MapiFile) as Long

Parameters

Session
[in] Handle to a Simple MAPI session. The value of the Session parameter must represent a valid session; it cannot be zero.
UIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.
MessageID
[in] The message identifier of the message to be read. The MessageID parameter is a variable-length string that is obtained from the MAPIFindNext and MAPISaveMail functions.
Flags
[in] Bitmask of flags. The following flags can be set:
MAPI_BODY_AS_FILE
MAPIReadMail should write the message text to a temporary file and add it as the first attachment in the attachment list.
MAPI_ENVELOPE_ONLY
MAPIReadMail should read the message header only. File attachments are not copied to temporary files, and neither temporary file names nor message text are written. Setting this flag makes MAPIReadMail processing faster.
MAPI_PEEK
MAPIReadMail does not mark the message as read. Marking a message as read affects its appearance in the user interface and generates a read receipt. If the messaging system does not support this flag, MAPIReadMail always marks the message as read. If MAPIReadMail encounters an error, it leaves the message unread.
MAPI_SUPPRESS_ATTACH
MAPIReadMail should not copy file attachments but should write message text into the MapiMessage type. MAPIReadMail ignores this flag if the calling application has set the MAPI_ENVELOPE_ONLY flag. Setting this flag makes MAPIReadMail processing faster.
Reserved
Reserved; must be zero.
Message
[out] A type set by MAPIReadMail to a message containing the message contents.
Originator
[out] The originator of the message.
Recips
[out] Array of recipients. This array is redimensioned as necessary to accommodate the number of recipients chosen by the user.
Files
[out] Array of attachment files written when the message is read. When MAPIReadMail is called, all message attachments are written to temporary files. It is the caller's responsibility to delete these files when they are no longer needed. When MAPI_ENVELOPE_ONLY or MAPI_SUPPRESS_ATTACH is set, no temporary files are written and no temporary names are filled into the file attachment descriptors. This array is redimensioned as necessary to accommodate the number of files attached by the user.

Return Values

MAPI_E_ATTACHMENT_WRITE_FAILURE
An attachment could not be written to a temporary file. Check directory permissions.
MAPI_E_DISK_FULL
The disk was full.
MAPI_E_FAILURE
One or more unspecified errors occurred while reading the message.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to read the message.
MAPI_E_INVALID_MESSAGE
An invalid message identifier was passed in the MessageID parameter.
MAPI_E_INVALID_SESSION
An invalid session handle was passed in the Session parameter. No message was retrieved.
MAPI_E_TOO_MANY_FILES
There were too many file attachments in the message. The message could not be read.
MAPI_E_TOO_MANY_RECIPIENTS
There were too many recipients of the message. The message could not be read.
SUCCESS_SUCCESS
The call succeeded and the message was read.

Remarks

The MAPIReadMail function returns one message, breaking the message content into the same parameters and types used in the MAPISendMail function. MAPIReadMail fills a block of memory with the MapiMessage type containing message elements. File attachments are saved to temporary files, and the names are returned to the caller in the message type. Recipients, attachments, and contents are copied from the message before MAPIReadMail returns to the caller, so later changes to the files do not affect the contents of the message.

A flag is provided to specify that only envelope informationis to be returned from the call. Another flag in the MapiMessage type specifies whether the message is marked as sent or unsent.

All strings are null-terminated and must be specified in the current character set or code page of the client application's operating system process. In Microsoft Windows, the character set is ANSI.

The sender, recipients, and file attachments are written into the appropriate parameters of the Visual Basic call. The Recips and Files parameters should be dynamically allocated arrays of their respective types.

The declaration of this function for the 32-bit Visual Basic runtime is:

MAPIReadMail(

Session As Long,
UIParam As Long,
MessageID As String,
Flags As Long,
Reserved As Long,
message As MAPIMessage,
Orig As MapiRecip,
RecipsOut() As MapiRecip,
FilesOut() As MapiFile) As Long


MAPIResolveName (VB)

The Visual Basic MAPIResolveName function transforms a message recipient's name as entered by a user to an unambiguous address list entry.

Quick Info

Header file: MAPIVB32.BAS

MAPIResolveName(

Session as Long,
 UIParam as Long,
UserName as String,
Flags as Long,
Reserved as Long,
Recipient as MapiRecip) as Long

Parameters

Session
[in] Session handle that represents a Simple MAPI session or zero. If the value of the Session parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. This temporary session can be an existing shared session or a new one. If necessary, a logon dialog box is displayed.
UIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.
UserName
[in] The name to be resolved.
Flags
[in] Bitmask of option flags. The following flags can be set:
MAPI_AB_NOMODIFY
The caller is requesting that the dialog box be read-only, prohibiting changes. MAPIResolveName ignores this flag if MAPI_DIALOG is not set.
MAPI_DIALOG
A dialog box should be displayed for name resolution. If this flag is not set and the name cannot be resolved, MAPIResolveName returns the MAPI_E_AMBIGUOUS_RECIPIENT value.
MAPI_LOGON_UI
A dialog box should be displayed to prompt the user to log on if required. When the MAPI_LOGON_UI flag is not set, the client application does not display a logon dialog box and returns an error value if the user is not logged on.
MAPI_NEW_SESSION
An attempt should be made to create a new session rather than acquire the environment's shared session. If the MAPI_NEW_SESSION flag is not set, MAPIResolveName uses an existing shared session.
Reserved
Reserved; must be zero.
Recipient
[out] A recipient-type set returned by MAPIResolveName if the resolution results in a single match. The type contains the recipient information of the resolved name. The descriptor can then be used in calls to the MAPISendMail, MAPISaveMail, and MAPIAddress functions.

Return Values

MAPI_E_AMBIGUOUS_RECIPIENT
The recipient requested has not been or could not be resolved to a unique address list entry.
MAPI_E_FAILURE
One or more unspecified errors occurred. The name was not resolved.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed. The name was not resolved.
MAPI_E_LOGIN_FAILURE
There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. The name was not resolved.
MAPI_E_NOT_SUPPORTED
The operation was not supported by the underlying messaging system.
MAPI_E_USER_ABORT
The user canceled the resolution. The name was not resolved.
SUCCESS_SUCCESS
The call succeeded and the name was resolved.

Remarks

The MAPIResolveName function resolves a message recipient's name (as entered by a user) to an unambiguous address list entry, optionally prompting the user to choose between possible entries, if necessary. A recipient descriptor containing fully resolved information about the entry is allocated and returned.

The declaration of this function for the 32-bit Visual Basic runtime is:

MAPIResolveName(

ByVal Session&,
ByVal UIParam&,
ByVal UserName$,
ByVal Flags&,
ByVal Reserved&,
Recipient As MapiRecip) As Long


MAPISaveMail (VB)

The Visual Basic MAPISaveMail function saves a message.

Quick Info

Header file: MAPIVB32.BAS

MAPISaveMail(

Session as Long,
 UIParam as Long,
Message as MapiMessage,
Recips as MapiRecip,
Files as MapiFile,
Flags as Long,
Reserved ByVal as Long,
MessageID as String) as Long

Parameters

Session
[in] Session handle that represents a Simple MAPI session or zero. If the value for the Session parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. This temporary session can be an existing shared session or a new one. If necessary, a logon dialog box is displayed.
UIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.
Message
[in] Contents of the message to be saved. Client applications can either ignore the Flags member of the MapiMessage type, or if the message has never been saved, can set the MAPI_SENT and MAPI_UNREAD flags.
Recips
[in] The first element in an array of recipients. When the value of the RecipCount member in the MapiMessage type is zero, this parameter is ignored. The recipient string can include either the recipient's name or the recipient's name-address pair. If only a name is specified, the name is resolved to an address using implementation-defined address-book search rules. If an address is also specified, a search for the name is not performed. The address is in an implementation-defined format and is assumed to have been obtained from the implementation some other way. When the address is specified, the name is used for display to the user and the address is used for delivery. When the EntryID member for a particular recipient is used, no search is performed and the display-name and address are ignored. (A name and address are associated with the EntryID within the messaging system.)
Files
[in] The first element in an array of attachment files written when the message is read. The number of attachments per message can be limited in some systems. If the limit is exceeded, the MAPI_E_TOO_MANY_FILES value is returned. When the value of the FileCount member in the MapiMessage type is zero, this parameter is ignored. Attachment files are read and attached to the message before the call returns. Do not attempt to display attachments outside the range of the message text.
Flags
[in] Bitmask of option flags. The following flags can be set:
MAPI_LOGON_UI
A dialog box should be displayed to prompt the user to log on if required. When the MAPI_LOGON_UI flag is not set, the client application does not display a logon dialog box and returns an error value if the user is not logged on. MAPISaveMail ignores this flag if the MessageID parameter is empty.
MAPI_LONG_MSGID
The returned message identifier is expected to be 512 characters. If this flag is set, the MessageID parameter must be large enough to accomodate 512 characters.
MAPI_NEW_SESSION
An attempt should be made to create a new session rather than acquire the environment's shared session. If the MAPI_NEW_SESSION flag is not set, MAPISaveMail uses an existing shared session.
Reserved
Reserved; must be zero.
MessageID
[in] A variable-length, caller-allocated string identifier for the message, returned either by the MAPIFindNext function or a previous call to MAPISaveMail, or a null string. If the MessageID parameter contains a valid message identifier, the message is overwritten. If MessageID contains a null string, a new message is created.

Return Values

MAPI_E_FAILURE
One or more unspecified errors occurred while saving the message. No message was saved.
MAPI_E_BAD_RECIPTYPE
The type of a recipient was not MAPI_TO, MAPI_CC, or MAPI_BCC. No message was sent.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to save the message. No message was saved.
MAPI_E_INVALID_MESSAGE
An invalid message identifier was passed in the MessageID parameter. No message was saved.
MAPI_E_INVALID_SESSION
An invalid session handle was passed in the Session parameter. No message was saved.
MAPI_E_LOGIN_FAILURE
There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No message was saved.
MAPI_E_NOT_SUPPORTED
The operation was not supported by the underlying messaging system.
MAPI_E_USER_ABORT
The user canceled the process. No message was saved.
SUCCESS_SUCCESS
The call succeeded and the message was saved.

Remarks

To replace an existing message, the caller first calls the MAPIFindNext function to locate the message to be replaced and then calls the MAPISaveMail function with the MessageID parameter set with a valid message identifier. The elements of the message identified by MessageID are replaced by the elements in the MapiMessage type pointed to by the Message parameter.

To create a new message, the caller passes an empty string for MessageID. New messages are saved in the folder appropriate for incoming messages of that class. The new message identifier is returned in MessageID on completion.

The MessageID parameter must be a variable-length string. The elements of the message identified by MessageID are replaced by the elements in the Message parameter. If MessageID is empty, a new message is created.

MAPISaveMail takes the recipients and file attachments from the Recips and Files parameters, which should each be the first element of dynamically allocated arrays of their respective types. These arrays are not redimensioned.

The declaration of this function for the 32-bit Visual Basic runtime is:

MAPISaveMail(

ByVal Session&,
ByVal UIParam&,
message As MAPIMessage,
Recipient() As MapiRecip,
File() As MapiFile,
ByVal Flags&,
ByVal Reserved&,
MsgID$) As Long


MAPISendDocuments (VB)

The Visual Basic MAPISendDocuments function sends a standard message with one or more attached files and a cover note. The cover note is a dialog box that allows the user to enter a list of recipients and an optional message.

Quick Info

Header file: MAPIVB32.BAS

MAPISendDocuments(

UIParam as Long,
DelimChar as String,
FullPaths as String,
FileNames as String,
Reserved as Long) as Long

Parameters

UIParam
[in] Parent window handle or zero, indicating that if a dialog box is displayed, it is application modal. If no dialog box is displayed during the call, the UIParam parameter is ignored.
DelimChar
[in] String containing the character used to delimit the names in the FullPaths and FileNames parameters. This character should not be used in filenames on your operating system.
FullPaths
[in] String containing the list of full paths, including drive letters, for the attached files. The list is formed by concatenating correctly formed file paths separated by the character specified in the DelimChar parameter. An example of a valid list is:
C:\TMP\TEMP1.DOC;C:\TMP\TEMP2.DOC

The files specified in FullPaths are added to the message as file attachments. If FullPaths contains an empty string, the Send Note dialog box is displayed with no attached files.

FileNames
[in] String containing the list of the original filenames as they should be displayed in the message. When multiple names are specified, the list is formed by concatenating the filenames separated by the character specified in the DelimChar parameter. An example is:
MEMO.DOC;EXPENSES.DOC

If there is no value for the FileNames parameter or if it is empty, MAPISendDocuments sets the filenames set to the filename values indicated by the FullPaths parameter.

Reserved
Reserved; must be zero.

Return Values

MAPI_E_ATTACHMENT_NOT_FOUND
An attachment could not be located in the specified path. Either the drive letter was invalid, the path was not found on that drive, or the file was not found in that path.
MAPI_E_ATTACHMENT_OPEN_FAILURE
One or more files in the FullPaths parameter could not be located. No message was sent.
MAPI_E_ATTACHMENT_WRITE_FAILURE
An attachment could not be written to a temporary file. Check directory permissions.
MAPI_E_FAILURE
One or more unspecified errors occurred while sending the message. It is not known if the message was sent.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed.
MAPI_E_LOGIN_FAILURE
There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No message was sent.
MAPI_E_USER_ABORT
The user canceled the process. No message was sent.
SUCCESS_SUCCESS
The call succeeded and the message was sent.

Remarks

Calling the MAPISendDocuments function displays a Send Note dialog box, which prompts the user to send a message with data file attachments. Attachments can include the active document or all the currently open documents in the Windows-based application that called MAPISendDocuments. This function is used primarily for calls from a macro or scripting language, often found in applications such as spreadsheet or word-processing programs.

There is no default identification when MAPISendDocuments is called; a standard logon dialog box appears. After the user provides a mailbox name and password, the Send Note dialog box appears.

The user's default messaging options are used as the default dialog box values. The caller is responsible for deleting temporary files created when using MAPISendDocuments.

The declaration of this function for the 32-bit Visual Basic runtime is:

MAPISendDocuments(

ByVal UIParam&,
ByVal DelimStr$,
ByVal FilePaths$,
ByVal FileNames$,
ByVal Reserved&) As Long


MAPISendMail (VB)

The Visual Basic MAPISendMail function sends a standard message.

Quick Info

Header file: MAPIVB32.BAS

MAPISendMail(

Session as Long,.
UIParam as Long,
Message as MapiMessage,
Recips as MapiRecip,
Files as MapiFile,
Flags as Long,
Reserved as Long) as Long

Parameters

Session
[in] Session handle that represents a Simple MAPI session or zero. If the value of the Session parameter is zero, MAPI logs on the user and creates a session that exists only for the duration of the call. This temporary session can be an existing shared session or a new one. If necessary, a logon dialog box is displayed.
UIParam
The parent window handle for the dialog box. A value of zero indicates that any dialog box displayed is application modal.
Message
[in] The message to be sent. An empty string indicates no text. Each paragraph should be terminated with either a carriage return (0x0d), a line feed (0x0a), or a carriage return–line feed pair (0x0d0a). The implementation wraps lines as appropriate. Implementations can place limits on the size of the text. The MAPI_E_TEXT_TOO_LARGE value is returned if this limit is exceeded. Client applications can set MAPI_RECEIPT_REQUESTED in the Flags member in the MapiMessage type pointed to by the Message parameter to prompt for a read report.
Recips
[in] The first element of an array of recipients. When the the value of the RecipCount member in the MapiRecip type pointed to by the Message parameter is zero, the Recips parameter is ignored. The Recips parameter can include either an entry identifier, the recipient's name, an address, or a name and address pair. Depending on the type and amount of information passed, MAPISendMail will perform varied levels of name resolution. If an entry identifier in the EntryID member for a particular recipient is specified, MAPISendMail performs no lookup and ignores the name and address. If only a name is specified, MAPISendMail resolves the name to a valid address using name resolution rules defined by Simple MAPI. If only an address is specified, MAPISendMail uses this address for both message delivery and for displaying the recipient name; no name resolution occurs. If both a name and address are specified, again MAPISendMail does not resolve the name. The specified name is used as the display name and not for resolution.
Files
[in] The first element of an array of attachment files written when the message is read. The number of attachments per message might be limited in some systems. If the limit is exceeded, the MAPI_E_TOO_MANY_FILES value is returned. When the value of the FileCount member in the MapiMessage type pointed to by the Message parameter is zero, the Files parameter is ignored. Attachment files are read and attached to the message before the call returns. Do not attempt to display attachments outside the range of the message text.
Flags
[in] Bitmask of option flags. The following flags can be set:
MAPI_DIALOG
A dialog box should be displayed to prompt the user for recipients and other sending options. Set the MAPI_LOGON_UI flag if MAPISendMail should display a dialog box to prompt the user to log on. When this flag is not set, MAPISendMail does not display a dialog box and returns a message if the user is not logged on.
MAPI_LOGON_UI
A dialog box should be displayed to prompt the user to log on if required. When the MAPI_LOGON_UI flag is not set, the client application does not display a logon dialog box and returns an error value if the user is not logged on. MAPISaveMail ignores this flag if the MessageID parameter is empty.
MAPI_NEW_SESSION
An attempt should be made to create a new session rather than acquire the environment's shared session. If the MAPI_NEW_SESSION flag is not set, MAPISendMail uses an existing shared session.
Reserved
Reserved; must be zero.

Return Values

MAPI_E_AMBIGUOUS_RECIPIENT
A recipient matched more than one of the recipient descriptor structures and MAPI_DIALOG was not set. No message was sent.
MAPI_E_ATTACHMENT_NOT_FOUND
The specified attachment was not found. No message was sent.
MAPI_E_ATTACHMENT_OPEN_FAILURE
The specified attachment could not be opened. No message was sent.
MAPI_E_FAILURE
One or more unspecified errors occurred. No message was sent.
MAPI_E_INSUFFICIENT_MEMORY
There was insufficient memory to proceed. No message was sent.
MAPI_E_LOGIN_FAILURE
There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No message was sent.
MAPI_E_TEXT_TOO_LARGE
The text in the message was too large. No message was sent.
MAPI_E_TOO_MANY_FILES
There were too many file attachments. No message was sent.
MAPI_E_TOO_MANY_RECIPIENTS
There were too many recipients. No message was sent.
MAPI_E_UNKNOWN_RECIPIENT
A recipient did not appear in the address list. No message was sent.
MAPI_E_USER_ABORT
The user canceled the process. No message was sent.
SUCCESS_SUCCESS
The call succeeded and the message was sent.

Remarks

The MAPISendMail function sends a standard message, with or without any user interaction. If recipient names, file attachments, or message text is provided, MAPISendMail can send the files or note without prompting users. If the optional parameters are specified and a dialog box is requested by use of the MAPI_DIALOG flag, the parameters provide the initial values for the dialog box.

File attachments are copied to the message before MAPISendMail returns; therefore, later changes to the files do not affect the contents of the message. The files must be closed when they are copied.

MAPISendMail takes the recipients and file attachments from the Recips and Files parameters, which should each be the first element of dynamically allocated arrays of their respective types. These arrays are not redimensioned.

All strings must be specified in the current character set or code page of the client application's operating system process.

The declaration of this function for the 32-bit Visual Basic runtime is:

MAPISendMail(

ByVal Session&,
ByVal UIParam&,
message As MAPIMessage,
Recipient() As MapiRecip,
File() As MapiFile,
ByVal Flags&,
ByVal Reserved&) As Long


Data Types for Visual Basic

Visual Basic uses a different set of calling and programming conventions than C and C++ use. Different structure and parameter definitions support the Visual Basic representation of strings and of structures, which in Visual Basic are called types. The following list describes how programming Simple MAPI Visual Basic applications differs from programming Simple MAPI C and C++ applications:

  • In C and C++, structures can contain pointers to other structures. Because the concept of a pointer is foreign to Visual Basic, extra function parameters are used instead of these complex structures.
  • Because the Visual Basic MAPI functions are declared, it is not necessary to explicitly cast passed arguments using ByVal.
  • An empty string in a string variable is equivalent to a NULL value.
  • Arrays must be dynamically declared so that they are redimensioned when the Simple MAPI function is executed.
  • Visual Basic manages memory, eliminating the need to call the MAPIFreeBuffer function.
  • All structures used in the Visual Basic version of Simple MAPI are Visual Basic types rather than C-language structures.
  • All strings used in the Visual Basic version of Simple MAPI are Visual Basic strings rather than C-language strings.

The following alphabetized entries contain documentation for the Visual Basic Data Types


MapiFile (VB)

The Visual Basic MapiFile type contains file attachment information.

Quick Info

Header file: MAPIVB32.BAS

Type MapiFile
     Reserved as Long
     Flags as Long
     Position as Long
     PathName as String
     FileName as String
     FileType as String
End Type

Members

Reserved
Reserved; must be zero.
Flags
Bitmask of flags. The following flags can be set:
MAPI_OLE
The attachment is an OLE object file attachment. If MAPI_OLE_STATIC is also set, the object is static. If neither flag is set, the attachment is simply a data file.
MAPI_OLE_STATIC
The attachment is a static OLE object file attachment.
Position
An integer used to determine where the attachment should be placed in the message text. Attachments replace the character found at a certain position in the message text; in other words, attachments replace the MapiMessage member NoteText[Position]. Applications cannot place two attachments in the same location within a message, and attachments cannot be placed beyond the end of the message text. MAPIReadMail does not return an attachment with the value of Position equal to –1 unless the MAPI_BODY_AS_FILE flag is set.
PathName
The full path of the attached file. The file should be closed before this call is made.
FileName
The filename seen by the recipient. This name can differ from the filename in the PathName member if temporary files are being used. If the FileName member is empty, the filename from PathName is used. If the attachment is an OLE object, FileName contains the class name of the object, such as "Microsoft Excel Worksheet."
FileType
A reserved descriptor that indicates to the recipient the type of the attached file. An empty string indicates an unknown or operating system–determined file type. With this release, you must use an empty string, "", for this parameter.

Remarks

Simple MAPI for Visual Basic supports the following kinds of attachments:

  • Data files
  • Embedded OLE objects
  • Static OLE objects

The Flags member determines the kind of attachment. OLE object files are file representations of OLE object streams. You can re-create an OLE object from the file by calling the OLE function OleLoadFromStream with an OLESTREAM object that reads the file contents. If an OLE file attachment is included in an outbound message, the OLE object stream should be written directly to the file used as the attachment.


MapiMessage (VB)

The Visual Basic MapiMessage type contains message information.

Quick Info

Header file: MAPIVB32.BAS

Type MapiMessage
     Reserved as Long
     Subject as String
     NoteText as String
     MessageType as String
     DateReceived as String
     ConversiondID as String
     Flags as Long
     Originator as Long
     RecipCount as Long
     FileCount as Long
End Type

Members

Reserved
Reserved; must be zero.
Subject
The subject text, limited to 256 characters or less. Messages saved with the MAPISaveMail function are not limited to 256 characters. An empty string indicates no subject text.
NoteText
A string containing text in the message. An empty string indicates no text. For inbound messages, each paragraph is terminated with a carriage return–line feed pair (0x0d0a). For outbound messages, paragraphs can be delimited with a carriage return, a line feed, or a carriage return–line feed pair (0x0d, 0x0a, or 0x0d0a).
MessageType
A message type string used by applications other than interpersonal electronic mail. An empty string indicates an interpersonal message (IPM) type.
DateReceived
A string indicating the date a message is received. The format is YYYY/MM/DD HH:MM; hours are measured on a 24-hour clock.
ConversationID
A string indicating the conversation thread identifier to which this message belongs.
Flags
Bitmask of flags. The following flags can be set:
MAPI_RECEIPT_REQUESTED
A receipt notification is requested.
MAPI_SENT
The message has been sent.
MAPI_UNREAD
The message has not been read.
Originator
A MapiFile type describing the sender of the message.
RecipCount
A count of the recipient descriptor types. A value of 0 indicates that no recipients are included.
FileCount
A count of the file attachment descriptor types. A value of 0 indicates that no file attachments are included.


MapiRecip (VB)

The Visual Basic MAPIRecip type contains recipient information.

Quick Info

Header file: MAPIVB32.BAS

Type MapiRecip
     Reserved as Long
     RecipClass as Long
     Name as String
     Address as String
     EIDSize as Long
     EntryID as String
End Type

Members

Reserved
Reserved; must be zero.
RecipClass
Classifies the recipient of the message. (Messages can be sorted by recipient class.) This member can also contain information about the originator of an inbound message.
Name
The name of the recipient that is displayed by the messaging system.
Address
Provider-specific message delivery data. This can be used by the messaging system to identify custom recipients who are not in an address list.
EIDSize
The size, in bytes, of the data in the EntryID member.
EntryID
A string used by the messaging system to uniquely identify the recipient. Unlike the contents of the Address member, this data is opaque and is not printable. The messaging system returns valid EntryID members for recipients or senders included in the address list.


Property Identifiers and Types

All MAPI properties are represented by property tags. A property tag is a 32-bit unsigned integer value that contains the property's identifier in the high order 16 bits and the property's type in the low order 16 bits. Property tags for all of the properties defined by MAPI are included in the MAPITAGS.H header file.

Property identifiers are used to indicate what a property is used for and who is responsible for it. Property identifiers are divided by MAPI into ranges; where an identifier falls in the range indicates its use and ownership.

Property types are used to indicate the format of the property's data. MAPI defines all of the valid types. Clients and service providers creating new properties must use one of these types. All of the property types are included in the MAPIDEFS.H header file.


List of Property Identifier Ranges

The following table summarizes the different ranges for property identifiers, describing the owner for the properties in each range.

Identifier range | Description
0000 | Reserved by MAPI for the special value PR_NULL.
0001 - 0BFF | Message envelope properties defined by MAPI.
0C00 - 0DFF | Recipient properties defined by MAPI.
0E00 - 0FFF | Non-transmittable message properties defined by MAPI.
1000 - 2FFF | Message content properties defined by MAPI.
3000 - 3FFF | Properties for objects other than messages and recipients defined by MAPI.
4000 - 57FF | Message envelope properties defined by transport providers.
5800 - 5FFF | Recipient properties defined by transport and address book providers.
6000 - 65FF | Non-transmittable message properties defined by clients.
6600 - 67FF | Non-transmittable properties defined by a service provider. These properties can be visible or invisible to users.
6800 - 7BFF | Message content properties for custom message classes defined by creators of those classes.
7C00 - 7FFF | Non-transmittable properties for custom message classes defined by creators of those classes.
8000 - FFFE | Properties defined by clients and occasionally service providers that are identified by name through the IMAPIProp::GetNamesFromIDs and IMAPIProp::GetIDsFromNames methods.
FFFF | Reserved by MAPI for the special error value PROP_ID_INVALID.

The range between 3000 and 3FFF is reserved for properties that are not related to either messages or recipients. MAPI divides this range into sub-ranges by types of object; the following table shows this further breakdown.

Identifier range | Type of property
3000 - 33FF | Common properties that appear on multiple objects, such as PR_DISPLAY_NAME and PR_ENTRYID.
3400 - 35FF | Message store properties
3600 - 36FF | Folder and address book container properties
3700 - 38FF | Attachment properties
3900 - 39FF | Address book properties
3A00 - 3BFF | Messaging user properties
3C00 - 3CFF | Distribution list properties
3D00 - 3DFF | Profile properties
3E00 - 3FFF | Status object properties


List of Property Types

MAPI supports both single-valued and multivalued properties. With a single-valued property, there is one value of the base type for the property. With a multivalued property, there are multiple values of the base type.

The single-valued and multivalued property types that are supported by MAPI are described as follows. For each single-valued type that has a corresponding multivalued type, the multivalued type appears in parentheses after the single-valued type.

PT_APPTIME (PT_MV_APPTIME)
Double value that is interpreted as date and time. The integer part is the date and the fraction part is the time. This property type is the same as the OLE type VT_DATE and is compatible with the Visual Basic time representation.
PT_BINARY (PT_MV_BINARY)
SBinary structure value, a counted byte array.
PT_BOOLEAN (PT_MV_12)
16-bit Boolean value where zero equals FALSE and non-zero equals TRUE. This property type is the same as the OLE type VT_BOOL.
PT_CLSID (PT_MV_CLSID)
CLSID structure value. This property type is the same as the OLE type VT_CLSID.
PT_CURRENCY (PT_MV_CURRENCY )
64-bit integer intepreted as decimal. This property type is compatible with the Visual Basic CURRENCY type and is the same as the OLE type VT_CY.
PT_DOUBLE (PT_MV_DOUBLE)
Double value; 64-bit floating point value. This property type is the same as PT_R8 and the OLE type VT_R8.
PT_ERROR
SCODE value; 32-bit unsigned integer. This property type is the same as the OLE type VT_ERROR.
PT_FLOAT (PT_MV_FLOAT)
32-bit floating point value. This property type is the same as PT_R4 and the OLE type VT_R4.
PT_I2 (PT_MV_I2)
Signed 16-bit integer. This property type is the same as PT_SHORT and the OLE type VT_I2.
PT_I4 (PT_MV_I4)
Signed or unsigned 32-bit integer. This property type is the same as PT_LONG and the OLE type VT_I4.
PT_I8 (PT_MV_I8)
Signed or unsigned 64-bit integer that uses the LARGE_INTEGER structure. This property type is the same as the OLE type VT_I8.
PT_LONG (PT_MV_LONG)
Signed or unsigned 32-bit integer. This property type is the same as PT_I4 and the OLE type VT_I4.
PT_LONGLONG (PT_MV_LONGLONG)
Signed or unsigned 64-bit integer. This property type is the same as PT_I8 and the OLE type VT_I8.
PT_NULL
Indicates no property value. This property type is reserved for use with interface methods and is the same as the OLE type VT_NULL.
PT_OBJECT
Pointer to an object that implements the IUnknown interface. This property type is similar to several OLE types such as VT_UNKNOWN.
PT_R4 (PT_MV_R4)
4-byte floating point value. This property type is the same as the OLE type VT_R4.
PT_R8 (PT_MV_R8)
8-byte floating point value. This property type is the same as the OLE type VT_DOUBLE.
PT_SHORT (PT_MV_SHORT)
Signed 16-bit integer. This property type is the same as PT_SHORT and the OLE type VT_I2.
PT_STRING8 (PT_MV_STRING8)
Null-terminated 8-bit character string. This property type is the same as the OLE type VT_LPSTR.
PT_SYSTIME (PT_MV_SYSTIME)
64-bit integer data and time value in the form of a FILETIME structure. This property type is the same as the OLE type VT_FILETIME.
PT_TSTRING (PT_MV_TSTRING)
Properties with this type have the property type reset to PT_UNICODE when compiling with the UNICODE symbol and to PT_STRING8 when not compiling with the UNICODE symbol. This property type is the same as the OLE type VT_LPSTR for resulting PT_STRING8 properties and VT_LPWSTR for PT_UNICODE properties
PT_UNSPECIFIED
Indicates that the property type is unknown. This property type is reserved for use with interface methods.


MAPI File Formats

MAPI publishes the formats of various configuration files that clients and service providers use to describe message services and their service providers, forms, and options for the MAPI debugging utility.

The following table describes these files by name or type:

Configuration file | Description
MAPISVC.INF | Contains configuration information for the MAPI subsystem, message services, and service providers.
Files with the .CFG extension | Contains configuration information for a form.
MAPIDBG.INI | Contains configuration information for the MAPIDBG utility for testing and debugging.

For detailed information about the file format of MAPISVC.INF, see File Format of MAPISVC.INF.

For detailed information about the file format of a form configuration file, see File Format of Form Configuration Files.

For detailed information about the file format of MAPIDBG.INI, see File Format of MAPIDBG.INI.


File Format of MAPISVC.INF

The MAPISVC.INF file acts as the central database for MAPI message service configuration information. MAPISVC.INF contains information about each of the message services installed on the workstation, information about the service providers that belong to each message service, and information about the MAPI subsystem. MAPISVC.INF is the primary source of information for profiles. That is, when a new profile is being built or an existing one modified, relevant information for each message service or service provider is copied from MAPISVC.INF.

MAPISVC.INF is divided into linked hierarchical sections:

  1. Section containing information that applies to all profiles. This section has three parts:
    • [Services] section, providing links to each of the subsequent message service sections.
    • [Help File Mappings] section, containing information about .HLP files provided by message services.
    • [Default Services] section, listing message services that make up a default installation.
  2. Section containing information that applies to individual message services. Entries in these sections provide links to subsequent service provider sections.
  3. Section containing information that applies to individual service providers in a message service.

The following illustration shows the organization of a typical MAPISVC.INF file. There are three message services: AB, MsgService, and MS. The name on the right hand side of the equal sign for each message service is the service's display name. Each message service has its own section elsewhere in the file that is linked to one or more service provider sections. There is one service provider section for every service provider that belongs to the message service. The AB and MS message services are single provider services whereas three service providers belong to the MsgService service.

MAPI provides a skeletal version of the MAPISVC.INF file that contains the entries for the MAPI subsystem. Each message service implementer adds entries that are appropriate both for their service and the service providers that belong to their service. Some of the entries are required while others are optional. For example, MAPI requires that you specify the name and path of each of the service providers in your message service. Without this information, they cannot be loaded.

You can add required and optional information in either the section for your message service and/or to the service provider sections. Where you put the information describing your message service depends on the number of service providers in the service. Because this information applies to each service provider in the service, you must make it accessible to all providers. Store it either in the message service section, the preferred option, or in all of the service provider sections. Storing information once avoid unnecessary replication and the need to keep multiple copies synchronized.

If your message service is a single provider service, store all of the message service information in the section for the service provider rather than in the section for the service. Accessing the service provider section is faster and more direct than accessing the message service section.

Store only public configuration data in the MAPISVC.INF file. Information that is private or requires extra protection, such as passwords or other credentials, should not be included in this file. Instead, opt either not to store information of this type at all or keep it in the profile as secure properties. Secure properties have built-in protection features such as encryption.

To update MAPISVC.INF
  1. Create a temporary file containing the information to be placed in MAPISVC.INF.
  2. Call the MERGEINI utility as follows, where TMP.INI is the name of the temporary file:
MERGEINI C:\MAPI\TMP.INI -m -q


MAPISVC.INF [Help File Mappings] Section

The [Help File Mappings] section contains entries that each map one message service to the file that provides Help for errors generated by the service. Entries in this section use the following format:

[Help File Mappings]
message service name = Help file name

The message service name is the name of the installed message service; the Help file name is the name of the file where the error information resides. The example following shows a typical [Help File Mappings] section that contains entries for three services: MAPI, the MsgService service, and the MS service.

[Help File Mappings]
MAPI=MAPI.HLP
MsgService=MYHELP.HLP
MS=STORE.HLP


MAPISVC.INF [Services] Section

The [Services] section lists the message services that are installed on a computer. Entries in this section use the following format:

[Services]
message-service section name = message service name

The message-service section name is a string defined by the message service that links this entry to a corresponding section for the service elsewhere in MAPISVC.INF. The message service name is the name of the installed service. The following section shows three message services: the Default Address Book, My Own Service, and the Message Store Service. These services are fictional, for illustration purposes only. Each message service implementer would substitute the appropriate entry for his or her message service in this section.

[Services]
AB=Default Address Book
MsgService=My Own Service
MS=Message Store Service

Each entry in this section has a corresponding section of its own where information for the message service is stored. For example, the corresponding section for the Default Address Book is called [AB].


MAPISVC.INF [Default Services] Section

The [Default Services] section lists all of the message services that are selected as default message services. These default message services are a subset of the message services listed in the [Services] section. When a profile configuration program creates a default profile, the message services in this section are automatically included.

The entries use the same format as entries in the [Services] section, as shown following:

[Default Services]
message-service section name = message service name

The following entries would be included in the [Default Services] section for the MAPISVC.INF shown in the earlier illustration:

[Default Services]
AB=Default Address Book
MsgService=My Own Service


MAPISVC.INF Message Service Sections

MAPISVC.INF includes one message service section for each of the entries listed in the [Services] section. There are two types of entries in these sections: one for setting certain properties and the other for listing names of sections that are related to the message service being configured.


Property Entries in MAPISVC.INF Message Service Sections

Entries that set properties use this format:

property tag = property value

The property tag can be a standard MAPI property tag if the configuration data represents one of the properties predefined by MAPI, or a nonstandard tag if the data does not represent a MAPI property. The nonstandard tag is made by combining the value for a property identifier with a property type. The result is an 8 digit hexadecimal number. The property value can be whatever makes sense for the property tag.

Message service sections can contain a variety of entries depending on the message service being configured. The following MAPI properties are typically included in a message services section in the listed format:

PR_DISPLAY_NAME = string
PR_SERVICE_DLL_NAME = name of DLL file
PR_SERVICE_ENTRY_NAME = name of entry point function
PR_SERVICE_SUPPORT_FILES = list of files
PR_SERVICE_DELETE_FILES = list of files
PR_RESOURCE_FLAGS = bitmask

The PR_DISPLAY_NAME string is the name of the message service that is shown in the user interface, the name that the user associates with the message service. The display name is an optional entry in MAPISVC.INF. Sometimes the display name will be made up of two parts; a part assigned by the message service and a part assigned by the user. If the user is responsible for assigning one of the parts, this is typically handled with a special dialog box known as a property sheet supplied by the message service under the control of a client application.

The information provided for the PR_SERVICE_DLL_NAME entry is the name of the DLL that contains the message service. The information provided for the PR_SERVICE_ENTRY_NAME entry is the name of the entry point function within that DLL that MAPI calls to configure the message service.

The files listed in the PR_SERVICE_SUPPORT_FILES entry are files that must be installed with the message service. Likewise, the files in the PR_SERVICE_DELETE_FILES entry must be removed when the message service is removed.

The PR_RESOURCE_FLAGS entry is a collection of options defined for the message service. For example, the SERVICE_SINGLE_COPY bit is set when the message service can only appear once in a given profile. The SERVICE_NO_PRIMARY_IDENTITY bit is set if the message service does not provide identity information.

Two examples of nonstandard property entries follow. The first entry specifies the path to the file used by the Default Address Book as the property value; the second entry specifies a numeric property value. Both entries have meaning specific to the AB message service.

6600001e=full path to file
66040003=integer


List Entries in MAPISVC.INF Message Service Sections

There are two types of section list entries: one that lists service provider sections and one that lists miscellaneous message service-specific sections. These two types of entries appear in MAPISVC.INF using the following formats:

Providers=provider section1, provider section2, ...... provider sectionX
Sections=section name1, section name2, ......section nameX

Each section in the Providers entry maps to an individual section providing configuration information for a service provider that belongs to the message service. Each section in the Sections entry maps to a section that contains extra configuration information needed by the message service. Message service implementers define extra sections when they want to include special information that does not fit in the standard sections. Message services that have complicated configurations typically use the Sections entry to add extra information. Every message services section has a Providers entry with at least one section in the list; not all message service sections have a Sections entry.

Two examples of message service sections follow. The first section is for the Default Address Book service from the earlier illustration, a straightforward message service with a single service provider. The second section is for the MsgService service, a more complex sample message service with three service providers.

[AB]
PR_DISPLAY_NAME=Default Address Book
Providers=AB Provider
PR_SERVICE_DLL_NAME=AB.DLL
PR_SERVICE_SUPPORT_FILES=AB.DLL
PR_SERVICE_ENTRY_NAME=DABServiceEntry
PR_RESOURCE_FLAGS=SERVICE_NO_PRIMARY_IDENTITY

[MsgService]
PR_DISPLAY_NAME=My Own Service
Providers=MsgService Prov1, MsgService Prov2, MsgService Prov3
Sections=First_Special_Section, Second_Special_Section
PR_SERVICE_DLL_NAME=MYSERV.DLL
PR_SERVICE_SUPPORT_FILES=MYSERV.DLL, MYXXX.DLL, MYZZZ.DLL
PR_SERVICE_ENTRY_NAME=MyServiceEntry
PR_RESOURCE_FLAGS=SERVICE_SINGLE_COPY
66040003=00000000

The Sections entry in the [MsgService] section lists two additional sections, one called [First_Special_Section] and the other called [Second_Special_Section]. The data that might appear in extra sections is meaningful to the specific message service. These sections appear following to illustrate extra sections.

[First_Special_Section]
UID=13DB0C8AA05101A9BB000AA002FC45A
66020003=01000000
66000003=00040000
66010003=06000000
66050003=03000000


MAPISVC.INF Service Provider Sections

MAPISVC.INF includes one service provider section for each of the entries listed in the Providers entry in the preceding message services section. Service provider sections are similar to message service sections in that both types of sections contain entries in this format:

property tag = property value

However, service provider sections and message service sections differ in that such property entries are the only type of entry included in service provider sections. There can be no additional or linked sections for service providers; all service provider information must be contained within the one section.

Some of the properties set in message service sections are also set in service provider sections because these properties make sense for both. The PR_DISPLAY_NAME property is an example. Both service providers and message services have a name that is used for display in the configuration user interface. Depending on the service provider, that name may or may not be the same. Other properties are specific to service providers.

Typical service provider sections include the following entries, all of which are required:

PR_DISPLAY_NAME = string
PR_PROVIDER_DISPLAY = string
PR_PROVIDER_DLL_NAME = name of DLL file
PR_RESOURCE_TYPE = long
PR_RESOURCE_FLAGS = bitmask

The PR_PROVIDER_DLL_NAME entry is similar to PR_SERVICE_DLL_NAME; it indicates the filename for the DLL that contains the service provider. Message service code may be stored with one of its service providers in the same DLL file or exist as a separate DLL. Note that no suffix is included in the entry regardless of the target platform; MAPI takes care of adding a suffix if necessary.

PR_RESOURCE_TYPE entry represents the type of service provider; service providers set it to the appropriate predefined constant. Valid values include MAPI_STORE_PROVIDER, MAPI_TRANSPORT_PROVIDER, and MAPI_AB_PROVIDER.

Another property entry that applies to both message services and service providers, the PR_RESOURCE_FLAGS entry indicates options. The settings for this property entry can differ depending on the service provider. For example, some message store providers might set PR_RESOURCE_FLAGS to STATUS_NO_DEFAULT_STORE if they can never operate as the default message store.

Three examples of service provider sections follow. The [AB Provider] section is the service provider section for the Default Address Book service. The [MsgService Prov1] and [MsgService Prov2] sections belong to My Own Service; the first is an address-book provider section and the second is a message-store provider section.

[AB Provider]
PR_DISPLAY_NAME=Default Address Book
PR_PROVIDER_DISPLAY=Default Address Book
PR_PROVIDER_DLL_NAME=AB.DLL
PR_RESOURCE_TYPE=MAPI_AB_PROVIDER
6600001e=C:\WINNT35\System32\DEFAB.TXT

[MsgService Prov1]
PR_DISPLAY_NAME=My Own Service
PR_PROVIDER_DISPLAY=My Own Address Book
PR_PROVIDER_DLL_NAME=MYXXX.DLL
PR_RESOURCE_TYPE=MAPI_AB_PROVIDER

[MsgService Prov2]
PR_DISPLAY_NAME=My Folders
PR_PROVIDER_DISPLAY=My Own Message Store
PR_RESOURCE_TYPE=MAPI_STORE_PROVIDER
PR_PROVIDER_DLL_NAME=MYZZZ.DLL
PR_RESOURCE_FLAGS=STATUS_NO_DEFAULT_STORE
66060003=00000000
66030003=00000000
34140102=78b2fa70aff711cd9bc800aa002fc45a
66090003=06000000
660A0003=03000000


File Format of Form Configuration Files

A form configuration file is a formatted file created by form developers to define a form. Because form configuration files are used by form managers to load forms, each form must be defined using a form configuration file. Form configuration files must have the .CFG filename extension. The file follows the general syntax of a Windows initialization file (.INI file). It is divided into named sections, and each section contains a series of entries and values. Values have one of the following types: string, displayed string, platform string, path, integer, or globally unique identifier, GUID. Form configuration files can be created with any text editor or word processor that is capable of saving text files.


Form Configuration File [Description] Section

The [Description] section lists all properties of the form that are associated with controls in the form's user interface, plus attributes that are used in locating the form. The MessageClass, Clsid, and DisplayName entries, which identify the name of the form's message class, its GUID, and the message class's display name, respectively, are required entries used to locate the form within the form library. The remaining entries are optional. The format of the [Description] section is:

[Description]
MessageClass = string
Clsid = guid
DisplayName = displayed string
SmallIcon = path
LargeIcon = path

Optional entries are:

Category = displayed string
Subcategory = displayed string
Comment = displayed string
Owner = displayed string
Number = displayed string
Version = integer
Locale = string
Hidden = integer
DesignerToolName = string
DesignerToolGuid = clsid
DesignerRuntimeGuid = clsid
ComposeInFolder = 0|1
ComposeCommand = string

The Category and Subcategory entries are used by form installers to set up the default categorization of forms within client application's user interface. For example a hierarchy could be set up where "Help Desk" is the category and "Software" and "Hardware" were the subcategories. This categorization can then be used by viewer applications to display messages in a more organized way. The Comment, Owner, and Number entries are all comment strings that appear in client application's user interface. These are form specific properties that can be used at the discretion of the form developer. For example, the Comment entry can be used to indicate the purpose of the form, the Owner entry used to indicate the person or organization responsible for maintaining the form, and the number used to track different version of the form. For the Comment entry, up to ten lines of comments can be included. The first line of comments uses the word "Comment" as the key, the second line of comments uses "Comment1" as the key, and so on through "Comment9."

The LargeIcon and SmallIcon entries are used to specify the path for the icon resources used to display icons in the client application's user interface, typically this is for table rows that include the PR_ICON or PR_MINI_ICON property columns. Icon file names can be specified as pathnames relative to the directory where the form configuration file is installed. The Version entry is used to indicate the version number of the form. Locale is the three-letter language identifier of the destination form library. A list of these identifiers can be found in the Win32 Programmer's Reference.

The Hidden entry indicates whether the form should be displayed in a form library provider's user interface: 1 indicates that the file is hidden and 0 indicates that the form is visible. An example form configuration file is shown following.

The ComposeInFolder entry controls whether the form is designed to be placed in the current folder or in the user's Inbox when the user saves the message while composing it: 1 indicates that the form should go in the current folder and 0 indicates that it should go in the Inbox.

The ComposeCommand entry is the string to be placed in the client application's compose menu. If this is not specified, the DisplayName entry will be used.

[Description]
MessageClass = IPM.Help
Clsid = {00020D31-0000-0000-C000-000000000046}
DisplayName = Help Desk Request Form

;optional entries

Category = Help Desk Requests
Subcategory = New Requests
Comment = Use this form to request network assistance
Owner = Help Desk
Number = 1
SmallIcon = C:\WINDOWS|EFORMS\HELPDESK\HDSMALL.ICO
LargeIcon = C:\WINDOWS|EFORMS\HELPDESK\HDLARGE.ICO
Version = 1.00
Locale = enu
Hidden = 0
ComposeInFolder = 0
ComposeCommand = &Help Desk Request


Form Configuration File [Extensions] Section

The [Extensions] section lists the extended attributes of the form, typically a named property set, which are any attributes beyond the basic ones listed in the [Description] section of the form configuration file. Extended attributes are properties returned from calls to the GetProps method of the IMAPIFormInfo object with the high bit set in the property tag. Client applications can determine a form's extended attributes, if any, by retrieving these tags. To do so, clients call the IMAPIProp::GetIDsFromNames method, passing in the names of the form's properties and call the IMAPIProp::GetProps method to get the properties.

Each entry in the [Extensions] section references a subsequent section that has a name with the syntax [Extension.string2].

[Extensions]
Extension.string1 = string2

Each extension property section defines one extension attribute using the MAPI named property syntax. The property type must be either PT_LONG or PT_STRING8. Property sets containing named strings are not supported. The format of the [Extension] section is:

[Extension.string2]
Type = integer
NmidPropset = guid
NmidInteger = integer
Value = string | integer

An example of an [Extensions] section and a subsequent related section is shown following.

[Extensions]
Extension.A = 1

[Extension.1]
Type = 30
NmidPropset = {00020D0C-0000-0000-C000-000000000046}
NmidInteger = 1
Value = 11220000


Form Configuration File [Platforms] Section

The [Platforms] section lists the complete set of platforms supported by this form. Each platform entry consists of the prefix Platform.string, where string is an arbitrary string code for the platform. Each string corresponds to the CPU entry of an individual [Platforms] sections. Each entry in a [Platforms] section defines a platform string that references a subsequent [Platform.platform string] section as shown here.

[Platforms]
Platform.string = platform string

Following is an example of a [Platforms] section.

[Platforms]
Platform.1 = NTx86
Platform.2 = Win95

Each [Platform.platform string] section contains the two required entries, CPU and OSVersion. The CPU entry specifies the processor, and the OSVersion entry specifies the operating system. Valid CPU values are described in the following table.

CPU Entry | Processor
Ix86 | Intel 80x86 and Pentium series processors, as well as equivalent processors from AMD, Cyrix, NextGen and other manufacturers.
MIPS | MIPS R4000 series processors.
AXP | Digital Equipment Corporation Alpha AXP processor.
PPC | Motorola Power PC series processors.
M68 | Mororola 68x00 series processors.

Valid OSVersion values are described in the following table.

OSVersion Entry | Operating System
Win3.1 | Windows 3.1 and Windows for Workgroups 3.11.
WinNT3.5 | Windows NT 3.5 or lower.
Win95 | Windows 95.
WinNT4.0 | Windows NT 4.0.
Mac7 | Macintosh System 7.

Additionally, the [Platform.platform string] section must contain either a File or LinkTo entry. The File entry lists the form server application executable file that the form library maintains and loads into a new subdirectory in the disk cache when the form is launched. If a LinkTo entry is used instead, it contains the name of a different platform string from which the File information is taken. This is useful if one version of a form supports multiple platforms.

The Registry entry is used whenever the File entry is used, it identifies the registry key for the form library where the executable file for the form server application is stored. Strings preceded by a backslash ( \ ) are placed at the root of the registry. Strings not preceded by a backslash are placed in the HKEY_CLASSES_ROOT\CLSID\GUID\ registry key, where GUID is the GUID of the form. The characters "%d" can be used to indicate the pathname of the directory from which the form configuration file has been read. This is useful for specifying other files with pathnames relative to the form configuration file. Multiple File or Registry entries can be specified by using File or Registry as a prefix followed by any other text. The format for the [Platform.platform string] section is:

[Platform.platform string]
CPU = string
OSVersion = string
File = path
LinkTo = string
Registry = string

The following are two example [Platform.platform string] sections, one using the File entry and one using the LinkTo entry.

[Platform.NTx86]
CPU = ix86
OSVersion = WinNT3.5
File = \helpdesk.exe
Registry = Local Server = %d\helpdesk.exe

[Platform.Win95]
CPU = ix86
OSVersion = Win95
LinkTo = NTx86

The [Platform.platform string] section is ignored when adding a form to the local form library, when it is assumed that the installer has placed the files constituting the message class handler into accessible local storage as named in the handler's section in the OLE registry, and has done the OLE registration in the system's registry.


Form Configuration File [Properties] Section

The [Properties] section lists the complete set of properties that the form uses and publishes; that is, the properties it creates in its custom messages that MAPI client applications can use when displaying columns, filtering contents tables, setting up search-results folders, and so on. Each entry in this property list references a subsequent [Property.string] section as shown following.

[Properties]
Property.string = string

The format of a [Property.string] section is:

[Property.string]
Type = integer
NmidPropset = guid
NmidString = string
NmidInteger = integer
DisplayName = string
Flags = integer
SpecialType = 0|1
Enum1 = string

Each [Property.string] section describes a single property. The Type entry specifies the MAPI property type, for example 3 (PT_I4), of the property. The NmidPropset entry is optional; together with either the NmidString entry or the NmidInteger entry, the NmidPropset entry gives the name of the property. NmidString gives the name of the property, while NmidInteger gives the identifier of the property. NmidString and NmidInteger are mutually exclusive.

If set, NmidPropset should contain the name of the property set; if absent, NmidPropset is set to a default based on the following rule: If NmidInteger is present and its value is less than 0x8000, NmidPropset is set to PS_MAPI. If the value of NmidInteger is set to an integer greater than 0x8000, or if it is absent, NmidPropset is set to PS_PUBLIC_STRINGS.

The DisplayName entry contains the label for the property. The SpecialType entry, if present and nonzero indicates that this property is a special property. At present, the only special property type defined is SpecialType = 1, which indicates string enumerated properties. If SpecialType is set to 1, the Enum1 entry references the [Enum1.string] section.

Following is an example of a [Properties] section and a [Properties.string] section.

[Properties]
Property.1 = Fire Hazard
Property.2 = Safe

[Property.Fire Hazard]
Type = 1
NmidPropSet = {E47F4480-8400-101B-934D-04021C007002]
NmidString = FireHazard
DisplayName = Fire Hazard
SpecialType = 1
Enum1 = HazardEnum

The Enum1 entry in the preceeding example references to a subsequent [Enum1.string] section describing an enumeration of a particular type. Such an enumeration associates the first property in the [Property.string] section with an integer property, called the index. Such an enumeration also contains a list of the possible values that the display-index pair can assume. Specifying a property type for the enumeration is unnecessary because by definition an Enum1 entry always has the PT_I4 type. The format for the [Enum1.string] section is:

[Enum1.string]
NmidPropset = guid
NmidString = string
NmidInteger = integer
EnumCount = integer
Val.integer.Display = string
Val.integer.Index = integer

The following is an example property definition for an enumerated property named Fire Hazard with possible values of Low, Medium, and High.

[Properties]
Property1 = Fire Hazard

[Enum1.HazardEnum]
IdxNmidPropset={E47F4480-8400-101B-934D-04021C007002]
IdxNmidString=FireHazardEnum
EnumCount = 3
Val.1.Display = Low
Val.1.Index = 1
Val.2.Display = Medium
Val.2.Index = 2
Val.3.Display = High
Val.3.Index = 3

[Enum1.string] sections can be used by applications for two purposes: to speed up the filtering of properties by using the index rather than the string and to sort by a different order than the alphanumeric order of the string values. For example, sorting could be done based on Low-Medium-High order rather than High-Medium-Low order.


Form Configuration File [Verbs] Section

The [Verbs] section lists the complete set of verbs supported by the form. The format of the [Verbs] section is:

[Verbs]
Verb1 = string

Following is an example of a [Verbs] section.

[Verbs]
Verb1=1
Verb2=2

Each verb is defined in a separate [Verb.string] section. A [Verb.string] section describes a single verb offered by the form. The DisplayName entry in a [Verb.string] section specifies the command name displayed in the user interface. The Code entry corresponds to the verb number passed in the IMAPIForm::DoVerb method. The syntax for the [Verb.string] section is:

[Verb.string]
DisplayName = displayed string
Code = integer
Flags = integer
Attribs = integer

Following is an example of a [Verb.string] section.

[Verb.1]
DisplayName=Reply
code=1
Flags=0
Attribs=2

[Verb.2]
DisplayName=Delete
Code=2
Flags=0
Attribs=2

Verbs listed in this section are retrieved by a client using the IMAPIFormInfo::CalcVerbSet method. Verbs are activated by calling the form's IMAPIForm::DoVerb method and passing it the code number of the verb to be performed.


File Format of MAPIDBG.INI

MAPIDBG.INI is a file that is used by MAPI's debugging utility to control various features of the MAPI subsystem. The file resides in the Windows directory and is organized in sections, similar to other Windows initialization files and MAPISVC.INF. Sections are labeled in the following format:

[SectionName] Section

There are several different sections as described in the following table.

Section name | Description
[General] | Controls debugging features common to all MAPI components.
[LocalHeapFailures] | Generates artificial allocation failures.
[Memory Management] | Controls debugging features in the MAPI memory allocator.
[MAPIX] | Controls debugging features in the MAPI subsystem.
[Remoting] | Controls debugging features in the interface marshalling and remoting processes.
[Simple MAPI] | Controls debugging features in Simple MAPI.
[Spooler] | Controls debugging features in the MAPI spooler.
[TNEF] | Controls debugging features in the MAPI TNEF facility.

Every section has one or more entries, formatted as follows:

EntryName = value

Most entries have no effect on retail versions of MAPI; they add features only in the debug versions. However, there are a few entries that affect both versions; the detailed descriptions of each section explicitly point out these exceptions.


MAPIDBG.INI [General] Section

The entries in this section control debugging features common to all MAPI components.

AssertBadBlocks = 0|1
If this entry is set to 1, the MAPIAllocateMore and MAPIFreeBuffer functions assert when passed an invalid memory address. If it is set to 0, they fail without asserting. This is useful for detecting bugs such as freeing uninitialized pointers and freeing blocks more than once. The default value is 1 — asserts are generated.
AssertLeaks = 0|1
If this entry is set to 1, MAPI asserts if any service provider DLL, IMAPISession interface, or IProfAdmin interface is not released before MAPI is shut down. The default value is 0 — asserts are not generated.
DebugTrace = 0|1
This entry controls trace output from several of the macros defined in MAPIDBG.H, including DebugTrace and the TraceSz and Assert group of macros. If this entry is set to 1, traces are written to the debug port using the Win32 function OutputDebugString, and can be captured using a debugger or a monitoring utility such as DBWIN.EXE (for Win16) or DEB.EXE (for Win32). If this entry is set to 0, no traces are written. The default value is 1 — traces are enabled.
EventLog = 0|1
On Windows NT only , if this entry is set to 1, all debug traces are written to the application event log instead of to the debug port. This is useful when debugging an NT service that uses MAPI. The default value is 0 — traces are written to the debug port, not the event log.
MemoryFillRandom = 0|1
This entry is obsolete. Use the FillMemory entry in the [Memory Management] section.
RetainDLLs = 0|1
If this entry is set to 1, MAPI does not call the Win32 function FreeLibrary to release provider DLLs although it does remove them from its internal data structures. This can occasionally be useful when pursuing bugs in provider startup and shutdown behavior. The default value is 0 — provider DLLs are freed.
TrapOnSameThread = 0|1
On Win32, if this entry is set to 1, the message dialog boxes generated by the Trap and Assert group of macros are created on the calling thread. If it is set to 0, the message box is generated on a separate thread to prevent reentering the message loop on the calling thread. The default value is 0 — message dialog boxes are generated on a separate thread.
VerboseTNEF = 0|1
If this entry is set to 1, the MAPI TNEF facility generates debug trace output for routine operations. If it is set to 0, TNEF generates traces only when errors occur. The default value is 1 — TNEF traces are verbose.
VirtualMemory = 0|1|4
This entry is obsolete. Use the VirtualMemory entry in the [Memory Management] section.


MAPIDBG.INI [Local Heap Failures] Section

The entries in this section control features in the MAPI memory allocator that generate artificial allocation failures to test how other components handle out of memory conditions.

AllocsToFirstFailure = number of allocations
This entry forces a memory allocation failure on the indicated attempt. Use it to test how well your client or provider handles memory allocation failures. The count includes blocks allocated by MAPI and by other components, not just by your own component.
FailureInterval = number of allocations
This entry forces repeated memory allocation failures at the specified interval after the count indicated by the AllocsToFirstFailure entry is reached. The count includes blocks allocated by MAPI and by other components, not just by your own component.
FailureSize = number of bytes
If this entry is nonzero, this entry forces every memory allocation request for the specified number of bytes or more to fail. This includes blocks allocated by MAPI and by other components, not just by your own component.


MAPIDBG.INI [Memory Management] Section

The entries in this section control debugging features in the MAPI memory allocator.

VirtualMemory = 0|1|4
If this entry is nonzero, memory allocations made through MAPI are surrounded by unaddressable memory on either side. This causes code that accesses memory outside the allocated block to fail immediately instead of corrupting memory and can be very helpful in isolating memory corruption bugs. If this entry is set to 4, the returned address is guaranteed to be aligned on a 4-byte boundary; if it is 1, the address of the returned memory block is unaligned. The default value is 0 — a normal heap is allocated.
AssertLeaks = 0|1
If this entry is set to 1, MAPI asserts if any memory allocated using the MAPI allocators has not been freed at the time MAPI is shut down. This is usually at the last MAPIUninitialize call; if the application fails to uninitialize MAPI, it occurs when the MAPI DLL is unloaded. The default value is 1 — generates asserts.
DumpLeaks = 0|1
If this entry is set to 1, MAPI outputs debug trace information regarding memory allocated using the MAPI allocators that were not freed by the time MAPI was shut down. The information includes a stack traceback (for Win32 only), size and location of the memory block, order in which the block was allocated, and the block's name (for internal MAPI allocations only). The default value is 1 — writes traces.
FillByte = 0xNN
This entry specifies the hexadecimal value to use for filling memory in the FillMemory entry. The default value is 0xFE.
FillMemory = 0|1
If this entry is set to 1, all memory blocks allocated by MAPI are filled with a fill byte after they're allocated and after they're freed. The default value is 1 — fills blocks.
SharedMemMaxSize = number of bytes
This entry limits the size of the MAPI shared memory area. It can be used to force allocation failures. The default value is 0 — the area is as big as necessary.

Anyone using the Microsoft RPC libraries who needs to use virtual allocation flags should set the VirtualMemory entry to 4 in both the [General] and [Memory Management] sections of MAPIDBG.INI. This includes anyone using EMSMDB.DLL or EMSABP.DLL. Microsoft RPC requires memory allocators to align memory at least as well as the operating system's allocator. The MAPI Virtual Memory allocator aligns on 4-byte boundaries when set to 4. Setting VirtualMemory to 1 does not do this in order to catch even single-byte overwrites immediately.

Enabling virtual allocation increases the MAPI subsystem's demand for system resources. On Win32, MAPI uses 64K of virtual address space for each allocation. On Win16, MAPI uses the GlobalAlloc function for each allocation, so it is possible to run out of selectors. Depending on the overall load your test scenario places on the system, you may need to narrow down the scenario enough to reproduce the problem without running out of system resources.

Clients and service providers can trace memory leaks by setting the DumpLeaks entry in the [Memory Management] section to 1, MAPI produces debug trace output for each leaked block of memory. For each leaked block, MAPI lists:

  • The name of the block and the heap it was allocated in, if available.
  • The address of the block.
  • The order in which the block was allocated, starting with 1 for the first block.
  • The size of the block.
  • The stack trace of the routine that allocated it (up to 20 frames, Win32 only).

One technique for turning the stack traceback into a usable symbolic trace is to save the debug output to a text file, get your application back into the WINDBG debugger in a steady state, and convert the hexadecimal numbers to symbols using the 'list near' command. This command prints the nearest symbols before and after a given address. It is helpful to use a macro in your preferred editor to convert the MAPI trace, which looks like this:

Memory leak 'Proxy/Stub Object' in MAPIX Internal Heap @ 004E0770,
    Allocation #18, Size: 48
[0] 6C4C3B2F
[1] 6C4C401D
[2] 77CF7AB7
[3] 77D30E30
[4] 77CC9076

into a string of "list near" commands that looks like this (it gives you the closest symbol before and after the address):

> ln 6C4C3B2F; ln  6C4C401D; ln 77CF7AB7; ln 77D30E30; ln 77CC9076

When run in the WINDBG command window, this string produces a list of symbols like the following (there are two symbols for each address, the first is almost always the one you want):

MAPI32!operator new(unsigned int)+0x2f
MAPI32!operator delete(void *)-0x31
MAPI32!StdPSFactory::CreateProxy(IUnknown *, const _GUID &,
    IRpcProxyBuffer * *, void * *)+0xbd
MAPI32!StdPSFactory::CreateStub(const _GUID &, IUnknown *, IRpcStubBuffer * *)-0xe3
OLE32!?CreateInterfaceProxy@CRemoteHdlr@@AAEPAVCPSIX@@ABU_GUID@@PAPAXPAJ@Z+0x7d
OLE32!?CreateInterfaceStub@CRemoteHdlr@@AAEPAVCPSIX@@ABU_GUID@@PAJ@Z-0xc1
OLE32!_IEnumUnknown_RemoteNext_Proxy@16+0xf
OLE32!_IEnumUnknown_RemoteNext_Thunk@4-0x6
OLE32!?AddRef@CRemoteHdlr@@UAGKXZ+0
OLE32!?GetRH@CStdIdentity@@AAEPAUIRemoteHdlr@@XZ-0x11

MAPI does not expose an API to trigger an allocation dump.

It is most efficient to address memory leaks as they occur instead of waiting until there is a large number.


MAPIDBG.INI [MAPIX] Section

The entries in this section control debugging features in the MAPI core and profile provider.

CheckNotifKeysOften = 0|1
If this entry is set to 1, the MAPI notification support methods validate their lists of entries and registrations before and after making any changes to them. The default value is 0 — no checks are performed.
CheckNotifTasksOften = 0|1
If this entry is set to 1, the MAPI notification support methods validate their list of active tasks before and after making any changes to it. The default value is 0 — no checks are performed.
DebugSpooler = path
If this entry is present, MAPI attempts to execute its value when it is time to launch the MAPI spooler instead of simply launching the executable. It can be used to launch a debugger, for instance. The default value is MAPISP32.EXE for Win32 or MAPISP.EXE for Win16.
DelaySpooler = seconds
This entry controls how long the MAPI spooler waits. The MAPI spooler process waits for a period of time immediately after being launched. This entry speeds up client startup by reducing contention between the client and MAPI spooler for CPU time and other resources. The default value is 15 seconds.
FlushRegistry = 0|1
If this entry is set to 1, the MAPI profile provider flushes the registry whenever a writeable profile section is released and at certain other times. If it is 0, MAPI never flushes the registry. Unlike most entries, this works for retail MAPI as well as the debug builds. The default value is 0 — the registry is not flushed.
SkipSystem = 0|1
If this entry is set to 0, MAPI tries the system directory first when loading the MAPI spooler or any service provider. If it is 1, MAPI loads those components in typical path order. Since most such components are installed in the system directory, it is faster to check there first. Unlike most entries, this works for retail MAPI as well as the debug builds. The default value is 0 — try the system directory first.
SpoolerAutoStartTimeout = seconds
This entry controls the length of time the client will wait for the MAPI spooler to start when it has been started automatically as the result of a client logon. The default value is 60 seconds.


MAPIDBG.INI [Simple MAPI] Section

The entries in this section control debugging features in Simple MAPI, including the long message identifier cache and the thunking layer.

DumpCacheContents = 0|1
If this entry is set to 1, the entire contents of the message identifier cache are dumped to debug trace each time the cache is accessed or modified. If it is 0, the cache is not dumped. The default value is 0 —the cache is not dumped.
MessageIDCacheGrow = number of entries
This entry controls the number of entries by which the cache grows when it is in runaway mode. When it is in circular buffer mode, its size does not change. The default value is 50 entries. This entry is found in EXCHNG.INI (for Win16) or EXCHNG32.INI (for Win32).
MessageIDCacheSize = number of entries
This entry controls the initial size of the cache and the size to which it is reset when returning to circular buffer mode. The default value is 10 entries. This entry is found in EXCHNG.INI (for Win16) or EXCHNG32.INI (for Win32).
TraceEntry = 0|1
If this entry is set to 1, the arguments to each Simple MAPI call are dumped to debug trace. The default value is 0 — calls are not traced.
TraceMessageIDCache = 0|1
If this entry is set to 1, normal operations in the message identifier cache generate debug trace output. If it is 0, only errors generate trace output. The default value is 0 — no traces are generated on normal operations.
TracePacket = 0|1
If this entry is set to 1, debug traces are generated for errors encountered on the send side of the Simple MAPI thunk layer. The default value is 0 — no traces are generated for thunk errors.
TraceServer = 0|1
If this entry is set to 1, debug traces are generated for errors and certain operations on the receive side of the Simple MAPI thunk layer. The default value is 0 — no traces are generated for thunk server errors.
TraceVerbose = 0|1
If this entry is set to 1, debug traces are generated for routine operations in the Simple MAPI thunk layer. The default value is 0 — no traces are generated for routine thunk operations.


MAPIDBG.INI [Spooler] Section

The entries in this section control debugging features in the MAPI spooler.

AlwaysRebuild = 0|1
If this entry is set to 1, the MAPI spooler rebuilds its merged outgoing queue on every outgoing queue notification. If it is 0, the queue is only rebuilt when opening a message store for the first time. The default value is 0 — rebuild the outgoing queue rarely.
AssertSessionLeaks = 0|1
If this entry is set to 1, the MAPI spooler asserts if it finds a reference count of greater than 1 when freeing memory for one of its IMAPISession objects. The default value is 0 — no assert for leaked spooler-side sessions.
LowPrioritySpooling = 0|1
If this entry is set to 1, the MAPI spooler gives its main thread below-normal base priority by calling the Win32 function SetThreadPriority and setting the THREAD_PRIORITY_BELOW_NORMAL value. If it is 0, the MAPI spooler runs at normal priority. The MAPI spooler continues to adjust its priority when flushing and performing other foreground operations regardless of this entry's value. The default value is 1 — the MAPI spooler runs at below-normal priority.
NonPersistanceTimeout = seconds
This entry controls the length of time the MAPI spooler waits before exiting. The MAPI spooler exits after the last client session has logged off, but not immediately. The default value is 20 seconds.
SafeMode = 0|1
If this entry is set to 1, then during its startup the MAPI spooler aborts submission on all messages in the outgoing queue and restarts the submission process from scratch. Submission is not aborted during subsequent rebuilds of the outgoing queue. If it is 0, the submission state is left intact. The default value is 0 — do not abort submission when the outgoing queue changes.
TraceHeartbeat = 0|1
If this entry or TraceEverything is set to 1, the MAPI spooler generates debug trace output during its normal idle time processing. The default value is 0 — no traces are generated for normal idle processing.
TraceHooks = 0|1
If this entry or TraceEverything is set to 1, the MAPI spooler generates debug trace output for normal operations involving MAPI spooler hook providers. The default value is 0 — no trace output is generated for normal hook operation.
TraceUploads = 0|1
If this entry or TraceEverything is set to 1, the MAPI spooler generates debug trace output for normal message transmission steps through message transports. The default value is 0 — no trace output is generated for normal message transmission.
TraceDownloads = 0|1
If this entry or TraceEverything is set to 1, the MAPI spooler generates debug trace output for normal message download steps from transport providers. The default value is 0 — no trace output is generated for normal downloading of messages.
TraceOutgoingQueues = 0|1
If this entry or TraceEverything is set to 1, the MAPI spooler generates debug trace output for normal notifications and other operations on the merged outgoing queue. The MAPI spooler maintains a merged outgoing queue that combines messages from outgoing queues of all open message stores that support message submission. The default value is 0 — no trace output is generated for normal outgoing queue processing.
TracePreprocessors = 0|1
If this entry or TraceEverything is set to 1, the MAPI spooler generates debug trace output when calling preprocessors. The default value is 0 — no trace output is generated for normal preprocessing operations.
TraceService = 0|1
If this entry or TraceEverything is set to 1, the MAPI spooler generates debug trace output when queuing, dequeueing, and processing service requests on behalf of MAPI and transport providers. The default value is 0 — no trace output is generated for normal service queue processing.
TraceVerbose = 0|1
If this entry or TraceEverything is set to 1, the MAPI spooler generates debug trace output in all categories for events that would otherwise be considered too frequent or insignificant to warrant trace output. The default value is 0 — the MAPI spooler does not generate trace output.
TraceYields = 0|1
If this entry or TraceEverything is set to 1, the MAPI spooler generates debug trace output when explicitly yielding the CPU to other processes, either on its own behalf or on behalf of a transport provider. The default value is 0 — no trace output is generated when yielding.
TraceEverything = 0|1
If this entry is set to 1, all the trace output requested by TraceHeartbeat, TraceHooks, TraceUploads, TraceDownloads, TraceOutgoingQueues, TracePreprocessors, TraceService, TraceVerbose, and TraceYields is generated, and the values of those entries are ignored. You cannot selectively turn off trace categories when TraceEverything is 1. The default value is 0 — entries for the individual categories control trace output.


MAPIDBG.INI [TNEF] Section

The entry in this section controls debugging features in the MAPI TNEF facility.

ForceUncompressedRTF = 0|1
If this entry is set to 1, TNEF assumes that all RTF text is uncompressed and checks the stream explicitly. If it is 0, TNEF assumes the text is compressed. The default value is 0.


MAPI Versions of 32-Bit Windows Functions

This appendix documents functions from the Win32 application programming interface (API) useful in the 16-bit environment used by MAPI client and server developers. Most of the functions documented in this appendix have limitations relative to their Win32 counterparts. Such limitations are noted for each function. Where possible, if the calling implementation requests unsupported functionality, the function returns a value that indicates failure.

Some of the 32-bit Windows functions documented here have been implemented specifically for MAPI. The MAPIWIN.H header file includes definitions to aid in developing single-source service providers that run on both Win32 and Win16 API platforms.

MAPI works only with filenames, and other strings passed to it, in the ANSI character set. Applications that use filenames in the OEM character set must convert them to ANSI before calling MAPI.


Accessing Win32 Information in the MAPIWIN.H Header File

MAPIWIN.H has three sections. The first section defines how to call an available function by different methods in Win16. Functions included in the first section manage per-instance global variables for dynamic-link libraries (DLLs). They work on the assumption that all of a DLL's per-instance global variables exist in a single block of memory.

The second section specifically defines for the Win16 environment functionality that is generally available in the Win32 environment. This section consists largely of Win32 file input-output functions that are not supported under Win16 but are implemented in MAPI.DLL using MS-DOS calls. Some functions of this type have limitations relative to their Win32 counterparts; the limitations are spelled out in this Appendix. The third section defines conventions that simplify certain common operations.

The following functions have no meaning on Win16, but Microsoft's MAPI implementation defines macros to make it easier to write common code:

CloseMutexHandle

CreateMutex

DeleteCriticalSection

EnterCriticalSection

InitializeCriticalSection

LeaveCriticalSection

ReleaseMutex

WaitforSingleObject


Syntax and Limitations for Win32 Functions Useful in MAPI Development

The remainder of this appendix lists Win32 functions useful to MAPI developers that have limits, adaptations, or differences when used in the MAPI development environment. Where applicable, these limitations are described. Where there are no limitations specifically defined, only the syntax of a function is included. For detailed descriptions of the Win32 functions, see the Win32 Programmer's Reference.

Three limitations apply to most of the Win32 functions that MAPI implements. Error codes returned from these functions or from GetLastError come from MS-DOS and may not always match the Win32 counterpart. Second, MAPI works only with filenames, and other strings passed to it, in the ANSI character set. Applications that use filenames in the OEM character set must convert them to ANSI before calling MAPI. And third, security attributes are ignored.


CloseHandle

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL CloseHandle(
  HANDLE hObject
)

Limitations

This function will close only file handles.


CompareFileTime

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

LONG CompareFileTime(
  CONST FILETIME * lpft1,
  CONST FILETIME * lpft2
)


CompareStringA

int CompareStringA(
  LCID Locale,
  DWORD dwCmpFlags,
  LPCSTR lpString1,
  int cchCount1,
  LPCSTR lpString2,
  int cchCount2
)


CompareStringW

int CompareStringW(
  LCID lcid,
  DWORD fdwStyle,
  LPCWSTR lpString1,
  int cch1,
  LPCWSTR lpString2,
  int cch2
)

Limitations

Only accurate for character values less than 128. Characters whose values are greater may not be compared accurately because the 16-bit implementation does not have the necessary Unicode mapping tables.


CopyFile

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL CopyFile(
  LPCTSTR lpszExistingFile,
  LPCTSTR lpszNewFile,
  BOOL fFailIfExists
)


CopyMemory

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

VOID CopyMemory (
  PVOID Destination,
  CONST VOID * Source,
  DWORD Length
)


CreateDirectory

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL CreateDirectory(
  LPCTSTR lpszPath,
  LPSECURITY_ATTRIBUTES lpsa
)

Limitations:

LPSECURITY_ATTRIBUTES is not supported; fails if non-null.


CreateFile

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

HANDLE CreateFile(
  LPCTSTR lpszName,
  DWORD fdwAccess,
  DWORD fdwShareMode,
  LPSECURITY_ATTRIBUTES lpsa,
  DWORD fdwCreate,
  DWORD fdwAttrsAndFlags,
  HANDLE hTemplateFile
)

Limitations

Several differences from ordinary Win32 usage occur when using the MAPI version of the CreateFile function:

  • dwFlagsAndAttributes and dwDesiredAccess are ignored.
  • lpSecurityAttributes is not supported and the function fails if it is not NULL.
  • hTemplateFile is not supported and the function fails if it is nonzero.


DeleteFile

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL DeleteFile(
  LPCTSTR lpszFileName
)


DosDateTimeToFileTime

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL DosDateTimeToFileTime(
  WORD wDOSDate,
  WORD wDOSTime,
  LPFILETIME lpft
)


FBadReadPtr

BOOL FBadReadPtr(
  CONST VOID * lpvPtr,
  UINT cbBytes
)

Limitations

The FBadReadPtr function behaves as does the IsBadReadPtr function but returns FALSE if the cbBytes parameter is zero regardless of the value of the lpvPtr parameter. This matches the behavior of Win32 IsBadReadPtr, rather than Win16 IsBadReadPtr.


FileTimeToLocalFileTime

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL FileTimeToLocalFileTime(
  CONST FILETIME * lpft,
  LPFILETIME lpftLocal
)

Limitations

Depends on time zone information in WIN.INI. The UI is included in the mail and fax control panel applet, and is set by the SetTimeZoneInformation call listed in this Appendix.


FileTimeToDosDateTime

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL FileTimeToDosDateTime(
  CONST FILETIME * lpft,
  LPWORD lpwDOSDate,
  LPWORD lpwDOSTime
)


FileTimeToSystemTime

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL FileTimeToSystemTime(
  CONST FILETIME * lpft,
  LPSYSTEMTIME lpst
)


FillMemory

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

VOID FillMemory (
  PVOID Destination,
  DWORD Length,
  BYTE Fill
)


FindClose

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL FindClose(
  HANDLE hFindFile
)


FindFirstFile

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

HANDLE FindFirstFile(
  LPCTSTR lpFileName,
  LPWIN32_FIND_DATA lpFindFileData
)

Limitations

The dwReserved0, dwReserved1 and cAlternateFileName members are not supported in the WIN32_FIND_DATA structure.


FindNextFile

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL FindNextFile(
  HANDLE hFindFile,
  LPWIN32_FIND_DATA lpFindFileData
)

Limitations

The dwReserved0, dwReserved1 and cAlternateFileName members are not supported in the WIN32_FIND_DATA structure.


GetACP

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

UINT GetACP(VOID)


GetCurrentProcessID

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

DWORD GetCurrentProcessId(VOID)

Limitations

Returns HTASK. Value is subject to reuse by the operating system.


GetFileAttributes

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

DWORD GetFileAttributes(
  LPCTSTR lpFileName
)

Limitations

This function won't work on Novell NetWare without FILESCAN rights.


GetFileSize

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

DWORD GetFileSize(
  HANDLE hFile,
  LPDWORD lpdwFileSizeHigh
)


GetFileTime

BOOL GetFileTime(
  HANDLE hFile,
  LPFILETIME lpftCreation,
  LPFILETIME lpftLastAccess,
  LPFILETIME lpftLastWrite
)

Limitations

The time that the file in question was last modified is supported, but not the file creation or access time. The function fails if either of the latter is requested.


GetFullPathName

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

DWORD GetFullPathName(
  LPCTSTR lpszFile,
  DWORD cchPath,
  LPTSTR lpszPath,
  LPTSTR * lpszFilePart
)

Limitations

This function does not handle ".." path components in lpFileName.


GetLastError

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

DWORD GetLastError(VOID)

Limitations

This function won't be as reliable as it is on Windows NT. If a function in this module fails because an unsupported feature was requested, no error is returned.


GetLocalTime

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

VOID GetLocalTime(
  LPSYSTEMTIME lpst
)

Limitations

This function returns the current time as local time.


GetSystemTime

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

VOID GetSystemTime(
  LPSYSTEMTIME lpst
)

Limitations

This function depends on the time zone and returns the current time as Greenwich mean time (GMT). Requires that an earlier call to SetTimeZoneInformation has been made to get the local time zone.


GetTempFileName

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

UINT GetTempFileName(
  LPCTSTR lpszPath,
  LPCTSTR lpszPrefix,
  UINT uUnique,
  LPTSTR lpszTempFile
)


GetTempFileName32

UINT WINAPI GetTempFileName32 (
  LPCSTR lpPathName,
  LPCSTR lpPrefixString,
  UINT uUnique,
  LPSTR lpTempFileName
)


GetTempPath

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

DWORD GetTempPath(
  DWORD cchBuffer,
  LPTSTR lpszTempPath
)


GetTimeZoneInformation

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

DWORD GetTimeZoneInformation(
  LPTIME_ZONE_INFORMATION lptzi
)


GetUserDefaultLCID

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

LCID GetUserDefaultLCID(VOID)


InterlockedDecrement

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

LONG InterlockedDecrement(
  LPLONG lplVal
)

Limitations

This function relies on cooperative multitasking.


InterlockedIncrement

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

LONG InterlockedIncrement(
  LPLONG lplVal
)

Limitations

This function relies on cooperative multitasking.


IsBadBoundedStringPtr

BOOL WINAPI IsBadBoundedStringPtr(
  const void FAR* lpsz,
  UINT cchMax
)


IsBadReadPtr

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL IsBadReadPtr(
  CONST VOID * lpvPtr,
  UINT cbBytes
)

Limitations

This function has been redefined to work as on the Win32 version of FBadReadPtr.


IsBadStringPtrW

BOOL IsBadStringPtrW(
  LPCWSTR lpszStr,
  UINT cchMax
)


LocalFileTimeToFileTime

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL LocalFileTimeToFileTime(
  CONST FILETIME * lpftLocal,
  LPFILETIME lpft
)

Limitations

Requires that an earlier call to SetTimeZoneInformation has been made to get the local time zone.


lstrlenW

int lstrlenW(
  LPCWSTR lpszString
)


lstrcmpW

int lstrcmpW(
  LPCWSTR lpszString1,
  LPCWSTR lpszString2
)


lstrcpyW

LPWSTR lstrcpyW(
  LPWSTR lpszString1,
  LPCWSTR lpszString2
)


MoveFile

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL MoveFile(
  LPCTSTR lpszExisting,
  LPCTSTR lpszNew
)

Limitations

The MAPI version of the MoveFile function won't move a directory. This function always works across drives, and it always performs a copy operation then deletes the original file, as opposed to truly performing a move operation.


MoveMemory

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

VOID MoveMemory (
  PVOID Destination,
  CONST VOID * Source,
  DWORD Length
)


MulDiv32

int MulDiv(
  int nMultiplicand,
  int nMultiplier,
  int nDivisor
)

Limitations

The MulDiv32 function supports the MULDIV macro contained in the MAPIWIN.H header file. It takes 32-bit arguments, unlike the native Win16 MulDiv. The MAPI MulDiv32 does not check for overflow on the nMultiplier parameter.


MultiByteToWideChar

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

int MultiByteToWideChar(
  UINT CodePage,
  DWORD dwFlags,
  LPCSTR lpMultiByteStr,
  int cchMultiByte,
  LPWSTR lpWideCharStr,
  int cchWideChar
)

Limitations

This function is only accurate for character values less than 128. Characters whose values are greater may not be compared accurately because the 16-bit implementation does not have the necessary Unicode mapping tables; it does not support Unicode single-byte conversion; works reliably only for ASCII characters.


ReadFile

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL ReadFile(
  HANDLE hFile,
  LPVOID lpBuffer,
  DWORD NumberOfBytesToRead,
  LPDWORD lpNumberOfBytesRead,
  LPOVERLAPPED lpOverlapped
)

Limitations

The count is limited to 64K. The lpOverlapped parameter is not supported and the function fails if lpOverlapped is not NULL.


RemoveDirectory

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL RemoveDirectory(
  LPCTSTR lpszDir
)


SetEndOfFile

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL SetEndOfFile(
  HANDLE hFile
)


SetFilePointer

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

DWORD SetFilePointer(
  HANDLE hFile,
  LONG lDistanceToMove,
  PLONG lpDistanceToMoveHigh,
  DWORD dwMoveMethod
)

Limitations

Distance is limited to 2 gigabytes (signed 32-bits). The SetFilePointer function fails if the lpDistanceToMoveHigh parameter is present and nonzero, unless the value it holds is the sign extension of a negative distance.


SetTimeZoneInformation

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL SetTimeZoneInformation(
  CONST TIME_ZONE_INFORMATION * lptzi
)

Limitations

Depends on time zone information in WIN.INI. The UI is included in the mail and fax control panel applet.


Sleep

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

VOID Sleep(
  DWORD cMilliseconds
)

Limitations

This function does not handle the alt+tab and alt+esc key combinations for task switching.


SystemTimeToFileTime

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL SystemTimeToFileTime(
  CONST SYSTEMTIME * lpst,
  LPFILETIME lpft
)


WideCharToMultiByte

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

int WideCharToMultiByte(
  UINT CodePage,
  DWORD dwFlags,
  LPCWSTR lpWideCharStr,
  int cchWideChar,
  LPSTR lpMultiByteStr,
  int cchMultiByte,
  LPCSTR lpDefaultChar,
  LPBOOL lpUsedDefaultChar
)

Limitations

This function is only accurate for character values less than 128. Characters whose values are greater may not be compared accurately because the 16-bit implementation does not have the necessary Unicode mapping tables; it does not support Unicode single-byte conversion; works reliably only for ASCII characters.


WriteFile

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

BOOL WriteFile(
  HANDLE hFile,
  PCVOID lpBuffer,
  DWORD nNumberOfBytesToWrite,
  PDWORD lpNumberOfBytesWritten,
  POVERLAPPED lpOverlapped
)

Limitations

The lpOverlapped parameter is not supported, and the function fails if it is not NULL.


ZeroMemory

This function entry is part of a MAPI-specific list of Win32 functions. For a complete description, see Win32 Functions.

VOID ZeroMemory (
  PVOID Destination,
  DWORD Length
)


Address Types

E-mail addresses in MAPI are defined by two properties. The address type, PR_ADDRTYPE, is a string property that names the messaging system the address is destined for. It is used by MAPI to assign responsibility for an e-mail address to the right transport provider. The e-mail address itself, PR_EMAIL_ADDRESS, is another string whose format varies depending upon PR_ADDRTYPE. It is not interpreted by MAPI, but by the transport provider and by the messaging system itself.

This appendix lists address types known to MAPI at this time and the corresponding e-mail address formats. Several of these address types, including SMTP, X400, and FAX are used by a large number of messaging systems. It is important that all MAPI components agree on the type name and address format for such common types, so they can interoperate smoothly. MAPI address book providers, MAPI transport providers, and gateways to messaging systems with MAPI-based clients should all take note of this specification.

To define a new address type, to make comments or suggestions about the information in this appendix, or to request more information, send e-mail to mapi@microsoft.com. The following table, and many of the address type specifications that follow, are work in progress.

Messaging system | Address type (PR_ADDRTYPE) | Owner or reference document
3Com 3+Mail | 3COM | 3Com (3+Open)
AT&T Easylink Services | ATT | AT&T
Lotus cc:Mail (proposed) | CCMAIL | IBM
CompuServe (proposed) | COMPUSERVE | Compuserve
Microsoft Exchange Server | EX | Microsoft
Facsimile | FAX MSFAX |
MCI MAIL | MCI | MCI Communications Corp.
Novell Message Handling System | MHS | Novell
Microsoft Mail Server for PC Networks | MS | Microsoft
Microsoft Mail Server for Appletalk Networks | MSA | Starnine Technologies®
The Microsoft Network | MSN | Microsoft
Professional Office System | PROFS |
Internet | SMTP | Internet Request for Comments (RFC) 822
SNA Distribution System | SNADS |
Telex (proposed) | TELEX |
X.400 Message Handling System | X400 | CCITT X.400 series specifications
X.500 Directory Services | X500 | CCITT X.500 series specifications


3+Mail (3COM)

This information is based on the Microsoft Mail Server for PC Networks gateway to 3+Mail. The custom recipient address is in the following format:

[3COM:UserName:Domain:Organization]

– Or –

[3COM:UserName]

– Or –

[3COM:UserAlias:Domain:Organization]


AT&T EasyLink (ATT)

This information is based on the Microsoft Mail for PC Networks gateway to AT&T Easylink. The custom recipient addresses are in the following formats:

AT&T Mail Address

[ATT:attmail!UserName]

attmail
The "gate name" for the AT&T Mail Network.
!
A delimiter.
UserName
A unique identifier for an individual user.

AT&T MailFAX

[ATT:fax!+FaxTelephoneNumber (/RecipientName) Option]

fax!
Indicates to the AT&T Mail Network that this message is being delivered to a fax machine.
+
Must be specified for AT&T Mail Network to insert the correct country access code.
FaxTelephoneNumber
The local fax telephone number, country code, area code and local exchange.
RecipientName
The recipient of the fax.
Options
Any AT&T Mail options.

An example of this address is:

[ATT:fax!+19085551234(/John Doe) delivery].

AT&T Telex

[ATT:telex!TelexNumber (/Attention)]

telex!
Indicates to the AT&T Mail Network that this is a message for a telex machine.
TelexNumber
The number of the telex machine to which the message is being delivered.
Attention
The name of the recipient of the message.

An example of this address is:

[ATT:telex!900123(Jones MFG CO/John Doe)].

AT&T MailPRINT

[ATT:printer!PrinterTelephoneNumber (/RecipientName) Options]

printer!
Indicates to the AT&T Mail Network that this message is being delivered to a printer.
PrinterTelephoneNumber
The local printer telephone number, country code, area code, and local exchange.
RecipientName
The recipient of the message.
Options
Any AT&T Mail option.

An example of this address type is:

[ATT:printer!19085551234 (/John Doe)].

AT&T Paper

[ATT:Address]

Address
The postal address is entered on one line with semicolons (;) used to separate the address parts. If the address contains a semicolon, surround it with quotation marks (";").

An example of this address type is:

[ATT:John Doe;123 Main Street; N.Y. 01234].


Facsimile (FAX, MSFAX)

Support is required for custom recipient addresses in the following format:

[FAX:Dialable | Name @ Canonical | SpecialDialing]

Dialable
A dialable fax phone number that consists of any of the following characters: 0-9, ( ), -, space. Examples are 64545 and 9, 1-206-8828080.
Name
Optional field used for inbound routing by Microsoft At Work Fax. MAPI providers that do not support Microsoft At Work Fax should simply ignore this field. The name field is interpreted by the receiving machine and can contain any information which helps route the fax to its intended recipient. For example, this field might be a recipient's e-mail name. This field can include the at sign character (@).
Canonical
Must be a canonical fax phone number. If a canonical fax phone number is included in the address, and the provider can process canonical numbers, the provider should always use the canonical number instead of the dialable phone number.
|
Separator character, ASCII Hex 0x7C. The separator between the subscriber number and special dialing instructions (such as a postfix or TIA/EIA/IS-141 subaddress) is optional. If the phone number is in canonical form and a separator is not present, then the special dialing instructions are assumed to begin with the first character in the local number which is not one of the following: the numerals 0-9, hyphen (-), space.
SpecialDialing
Must be a postfix, TIA/EIA/IS-141 subaddress or ISDN subaddress. MAPI 1.0 providers can optionally support these special dialing extensions.

Examples of this address type are:

[FAX:936-7329]
[FAX:1-206-9367329]
[FAX:936-7329 | +1 (206) 936-7329]
[FAX:936-7329 | tedst@ +1 (206) 936-7329]
[FAX:936-7329 | tedst@+1 (206) 936-7329]
[FAX:936-7329 | +1 (206) 9367329|#546]
[FAX:936-7329 | +1 (206) 9364344|,,,,,567]

Note Some service providers create 'MSFAX' formatted addresses but with the 'FAX' address type. Providers can either handle these addresses, or not accept responsibility for them as they see fit; either method is acceptable.

Support is optional (but recommended) for custom recipient addresses in the following format:

[MSFAX:Name@ PhoneNumber | SpecialDialing]

Name
Optional field used for inbound routing by Microsoft At Work Fax. MAPI providers that do not support Microsoft At Work Fax should simply ignore this field. The name field is interpreted by the receiving machine and can contain any information which helps route the fax to its intended recipient. For example, this field might be a recipient's e-mail name. This field can include the at sign character (@).
PhoneNumber
Must be a canonical phone number or dialable phone number.
|
Separator character, ASCII Hex 7c. This is the separator between the subscriber number and special dialing instructions (such as a postfix or TIA/EIA/IS-141 subaddress). This separator is optional. If the phone number is in canonical form and a separator is not present, then the special dialing instructions are assumed to begin with the first character in the local number which is not one of the following: the numerals 0-9, hyphen (-), period (.), and space.
DialablePhoneNumber
A dialable address is a phone number that consists of any of the following characters: the numerals 0-9, letters A-D, asterisk (*), pound (#), comma (,), exclamation mark (!), uppercase and lowercase w (W, w), uppercase and lowercase p (P, p), uppercase and lowercase t (T, t), at sign (@), dollar sign ($), question mark (?), hyphen (-), period (.), and space. For example 64545. Dialable addresses are intended to be used to represent internal phone extensions.
SpecialDialing
Must be a postfix, TIA/EIA/IS-141 subaddress or ISDN subaddress. MAPI 1.0 providers can optionally support these special dialing extensions.

Examples of this address type are:

[MSFAX: 936-7329]
[MSFAX: +1 (206) 936-7329]
[MSFAX: tedst@+1 (206) 936-7329]
[MSFAX: +1 (206) 9367329|#546]
[MSFAX: +1 (206) 9364344|,,,,,567]

The following table includes descriptions of the components of this address:

Component | Description
canonical phone number | A phone number in the form: +CountryCode space (AreaCode) space LocalNumber. Examples are +1 (206) 936-4479 and +43 443444. CountryCode and AreaCode can only contain the numerals 0 through 9. If the area code is present it must be preceded by exactly one ASCII left parenthesis character (0x28), and be followed by exactly one ASCII right parenthesis character (0x29) and one ASCII space character (0x20). The local number must contain one or more of the numerals 0 through 9 but must not include any of the following characters: AaBbCcDdPpTtWw*#!,@$?;()|^ CRLF
special dialing | Must be a postfix, TIA/EIA/IS-141 subaddress or ISDN subaddress. MAPI 1.0 providers can optionally support these special dialing extensions.
postfix | A string of dialing control characters and digits used to complete calls which require DTMF routing, manual dialing, or pauses in the dialing sequence. The string must begin with one of the following characters: $ , ? W w @ and can contain any of the following characters: 0-9 A-D * # , ! W w P p T t @ $ ?. An example is +1 (206) 9367329|,,,,,567. This waits for several seconds after the main number is dialed before entering the DTMF tones 567.
TIA/EIA/IS-141 subaddress | Used for inbound routing according to the U.S. standard TIA/EIA/IS-141. MAPI 1.0 providers that cannot transmit this subaddress information should remove this field before dialing. This field must begin with the number sign (#). In typical use, this value uniquely identifies a recipient. An example is +1 (206) 9367329|#543. This example enables inbound routing to employee 543
ISDN Subaddress | For faxing over ISDN. MAPI 1.0 providers that cannot transmit ISDN subaddresses should remove this field before dialing. An ISDN subaddress can begin with any character except the following: # $ , ? W w @
$ | Wait for "billing signal", such as a credit card prompt tone.
, | Indicates that dialing is to be paused. The duration of a pause is device specific.
? | Indicates that the user is to be prompted before continuing with dialing.
W w | Dialing should proceed only after a dialing tone has been detected.
@ | Indicates that dialing is to "wait for quiet answer" before dialing the remainder of the number. This means to wait for at least one ringback tone followed by several seconds of silence.
P p | Indicates that pulse dialing is to be used for the digits following it.
T t | Indicates that tone (DTMF) dialing is to be used for the digits following it.

Note Microsoft supports two FAX address formats. FAX is intended to be used for compatibility with downlevel systems — including the Microsoft Mail for PC Networks FAX gateway. Although it is optional, all transport writers are encouraged to support and use the MSFAX standard. The 'FAX' standard will likely be eliminated in favor of the 'MSFAX' standard in a future release.

For more information on dialable and canonical addresses, see the Win32 Telephony (TAPI) documentation.


MCI MAIL (MCI)

This information is based on the Microsoft Mail for PC Networks gateway to MCI MAIL. It may be incomplete or out of date in certain respects. The custom recipient address is in the following format:

[MCI:UserName\r EMS:EMSName\r MBX:MCIMailbox]

MCI
MCI MAIL address indicator.
UserName
Name of mail recipient. Not used for mail delivery.
EMS
Indicates the name or number in the next field is the recipient's REMS (remote e-mail system) account.
EMSName
The actual EMS name or number. This can also be an MCI service provided by MCI; consult MCI Help for more information.
MBX
Indicates this is additional information required by the remote system.
MCIMailbox
Actual MBX (address) for the recipient on the remote system. If the remote system is Microsoft Mail, MCIMailbox is the full Microsoft Mail address. You can only have one complete MBX address.

There is always a space in front of the EMS: token and another space in front of each MBX: token. These spaces are required. The carriage-return symbol at the end of the line is in addition to whatever code your text editor inserts.

The actual message text requires a header separator after the TEXT: token. That is, the first line after TEXT: should be a line of 78 dash (-) characters to separate the header from the message text. Include these 78 characters in the TEXT count.

An example of this address type is:

[MCI:John Doe\r EMS:MCI Mail\r MBX:123-4567\r]

The following are other MCI addresses:

MCI MAIL

Example:

[MCI:John Doe at MCI\r EMS:MCI Mail\r MBX:123-4567]

MCI Paper

Example:

[MCI:John Doe\r EMS:MCI Mail\r MBX:Company:ABC, Inc.\r
MBX:Country:Canada\r MBX:Line1:100 - 123 Main Street\r
MBX:Line2:\r MBX:City:Vancouver\r MBX:State:B.C.\r
MBX:Code:V6B 1A1]

EMS

This address type is for Microsoft Mail recipients.

Example:

[MCI:John Doe\r EMS:ems_name\r
MBX:network/postoffice/JohnDoe\r
MBX:\r MBX:\r MBX:\r MBX:\r MBX:]

REMS

This address type is for non-Microsoft Mail recipients.

Example:

[MCI:John Doe\r EMS:Internet\r MBX:JohnDoe@aaa.bbb.bc.ca\r
MBX:\r MBX:\r MBX:\r MBX:\r MBX:]

TELEX

Example:

[MCI:John Doe\r EMS:MCI Mail\r MBX:Country:-\r
MBX:Telex:6501234567\r MBX:Answerback:6507654321]

Fax

Example:

[MCI:John Doe\r EMS:MCI Mail\r MBX:FAXNo:604-123-4567\r
MBX:Retry:4.0\r MBX:Company:ABC Company Inc.\r
MBX:SFax:604-111-1111\r MBX:SPhone:604-222-2222]


Novell Message Handling System (MHS)

This information is based on the Microsoft Mail for PC Networks gateway to MHS and the SMF 71 specification. It may be incomplete or out of date in certain respects. The custom recipient address is in the following format:

[MHS:User@Host] for a MHS user on MHS host.

Host
The name of the MHS host.

– Or –

[MHS:Mailbox@Gateway] for a MSMail user on a MHS gateway

Mailbox
8 ASCII characters
Gateway
The name of the MHS gateway, not MHS host.

– Or –

[MHS:User@Gateway {Network/Postoffice/Mailbox}] for a MSMail user on MHS gateway/downstream postoffice.

User
A place holder.
Network/Postoffice/Mailbox
MSMail for PC Networks address.

– Or –

[MHS:User@Gateway LocalAddress] for non-MSMail user on MHS gateway (general case).

LocalAddress
The user's native address. For example, MSMail, X.400.


Microsoft Mail for PC Networks (MS)

The custom recipient address is in the following format:

[MS:Network/PostOffice/UserID]

Network
A 10 char (max) name of a MICROSOFT Mail Network.
PostOffice
A 10 character (max) Postoffice name.
UserID
A 10 chararacter (max) name of a PC Mail user.
/
A delimiter.

This address type is also used at times by Microsoft Exchange Server.


Microsoft Mail for Appletalk Networks (MSA)

The custom recipient address is in the following format:

[MSA:UserID@MS Mail Server]

UserID
Name of Microsoft Mail for AppleTalk user.
MS Mail Server
Name of Microsoft Mail for AppleTalk server.


The Microsoft Network (MSN)

The custom recipient address is in the following format:

[MSN:UserID]

UserID
The name of the MSN member. For example, [MSN:patsmith].

MSN allows the sender to change the recipient's display name by using the following addressing style: Pat Smith[MSN:PatSm]. This will resolve on the client to a friendly name of 'Pat Smith' and an address alias of PatSm. The recipient will see the friendly name when they read the message.


Professional Office System (PROFS)

This information is based on the Microsoft Mail for PC Networks gateway to PROFS. The GATEWAY field is part of the gateway architecture, not the PROFS address. The custom recipient address is in the following format:

[PROFS:Gateway/Node/UserID]

Gateway
The gateway name. Limited to 10 characters.
Node
VM node name. Limited to 8 characters.
UserID
VM user ID. Limited to 8 characters.


Internet (SMTP)

The format of Internet e-mail addresses is defined in RFC 822. MAPI components should handle any address that complies with that standard. However, there is a particular form of RFC 822 address that best encodes MAPI addresses:

display name <e-mail address>

The angle brackets are included as literals. Blanks are common in display names; they need not be quoted. A typical address might look like this one, which belongs to one of the coauthors of RFC 1521:

Nathaniel Borenstein <nsb@bellcore.com>

If the display name contains characters that have special meaning in SMTP addresses, such as < or @, the entire display name should be quoted using double quotes. On outbound mail, if the total length of the e-mail address plus display name exceeds 255 characters, the display name should be dropped.


SNA Distribution System (SNADS)

This information is based on the Microsoft Mail for PC Networks gateway to SNADS. The GATEWAY field is part of the gateway architecture, not the SNADS address. The custom recipient address is in the following format:

[SNADS:Gateway/DistributionGroupName/DistributionElementName]

Gateway
Gateway name. Limited to 10 characters.
DistributionGroupName
Distribution Group Name. Limited to 8 characters.
DistributionElementName
Distribution Element Name. Limited to 8 characters.


Telex (TELEX) - Proposed

This address type definition is only a proposal. Comments and suggestions are welcome. The custom recipient address is in the following format:

[TELEX:Recipient@TelexNumber]

At least a telex number is required. For example [TELEX:foobar @ 1-2066354657].


X.400 Message Handling System (X400)

This information is based on the Microsoft Mail for PC Networks gateway to X.400 mail systems. Certain fields, particularly "DDA," and the length limitations may not apply in all X.400-based messaging systems. The custom recipient address is in the following format:

[X400:g=GivenName;s=Surname;o=Organization;ou=OrganizationalUnit; p=PRMD;a=ADMD;c=Country;]

Label | Description | Maximum Length
G= | Given name | 16
I= | Initials | 5
S= | Surname (required if G, I or Q are used) | 40
Q= | Generation Qualifier | 3
CN= | Common name | 64
X.121= | X.121 address | 15
N-ID= | User agent numeric identifier | 32
T-TY= | Terminal type | 3
T-ID= | Terminal identifier | 24
O= | Organization | 64
OU1= | Organizational unit #1 | 32
OU2= | Organizational unit #2 | 32
OU3= | Organizational unit #3 | 32
OU4= | Organizational unit #4 | 32
P= | Private Management Domain (PRMD) | 16
A= | Administrative Management Domain (ADMD - required) | 16
C= | Country (required) | 2 or 3
DDA= | Domain Defined Attribute (format => dda:<type>=<value>;) | 8, 128


X.500 Directory Service (X500)

This address type is based on CCITT Recommendations X.500 and the associated APIA - X/OPEN API specifications and the proposed annex to F.401, Annex F. The custom recipient address is in the following format:

[X500:/C=CountryCode/O=Organization/OU=OrganizationUnit/CN=CommonName]

The following field length limits apply:

Field | Length limit
CountryCode | 2 characters
Organization | Up to 64 characters
OrganizationUnit | Up to 32 characters
CommonName |

The following guidelines apply:

  • Labels can be uppercase or lowercase.
  • Delimiters are slash marks (/) and must be specified before the first value as well as between values.
  • Delimiters can be followed by a space.

An example of this address is:

[X500:/ c=US/ o=Microsoft/ ou=WGA/ cn=TedSt]


Transport-Neutral Encapsulation Format (TNEF)

TNEF is a format for converting a set of MAPI properties—a MAPI message—into a serial data stream. The TNEF functions are primarily used by transport providers that need to encode MAPI message properties for transmission through a messaging system that does not support those properties directly. For example, an SMTP-based transport uses TNEF to encode properties like PR_SENT_REPRESENTING, which do not have direct representations in the structure of an SMTP message.

The TNEF implementation defines several TNEF-specific attributes, each of which corresponds to a particular MAPI property. These attributes are used to encode their respective MAPI properties into the TNEF stream. In addition, a special attribute is defined that can be used to encapsulate any MAPI property that does not have a specific attribute corresponding to it. The reason these attributes are defined — instead of simply using a uniform encoding method for all MAPI properties — is to enable backward compatibility with non-MAPI-compliant software that is using TNEF such as Microsoft Mail 3.x and its transport providers.

The remainder of this appendix describes the structure and syntax of a TNEF stream, the mapping between MAPI properties and TNEF attributes, and important considerations for certain TNEF attributes.


TNEF Stream Structure

A TNEF stream begins with a 32-bit signature that identifies the stream as a TNEF stream. Following the signature is a 16-bit unsigned integer that is used as a key to cross-reference attachments to their location within the tagged message text. The remainder of the stream is a sequence of TNEF attributes. Message attributes appear first in the TNEF stream, and attachment attributes follow. Attributes belonging to a particular attachment are grouped together, beginning with the attAttachRenddata attribute.

Most of the constant values used in TNEF streams are defined in the TNEF.H header file. Notably, TNEF_SIGNATURE, LVL_MESSAGE, LVL_ATTACHMENT, and all the TNEF attribute identifiers are defined in this file. Other constants have the values indicated by their interpretation to a C language compiler. Typically, such constants are used to give the sizes of the following item. For example, sizeof(ULONG) in an item's definition indicates that an integer representing the size of the following unsigned long integer should occur in that place in the TNEF stream.

All integers in a TNEF stream are stored in little-endian binary form, but are shown in hexadecimal throughout this appendix. Checksum values are simply 16-bit unsigned integers that are the sum, modulo 65536, of the bytes of data that the checksum applies to. All attribute lengths are unsigned long integers, including any terminating null characters.

The key is a nonzero, 16-bit unsigned integer that signifies the initial value of the attachment reference keys. The attachment reference keys are assigned to each attachment sequentially beginning with the initial value, that is passed to the OpenTnefStream function by the service provider that is using TNEF. The service provider should generate a random initial value for the key to minimize the chance that two messages use the same key.

The TNEF implementation uses attribute identifiers to map attributes to their corresponding MAPI properties. An attribute identifier is a 32-bit unsigned integer made up of two word values. The high-order word indicates the data type, such as string or binary, and the low-order word identifies the particular attribute. The data types in the high order word are:

Type | Value
atpTriples | 0x0000
atpString | 0x0001
atpText | 0x0002
atpDate | 0x0003
atpShort | 0x0004
atpLong | 0x0005
atpByte | 0x0006
atpWord | 0x0007
atpDword | 0x0008
atpMax | 0x0009

The low-order word values for each attribute are defined in the TNEF.H header file.


TNEF Stream Syntax

This topic presents a Bakus-Nauer like description of the TNEF stream syntax. In this description, nonterminal elements that have a further definition are in italics. Constants and literal items are in bold. Sequences of elements are listed in order on a single line. For example, the Stream item consists of the constant TNEF_SIGNATURE, followed by a Key, followed by an Object. When an item has more than one possible implementation, the alternatives are listed on consecutive lines. For example, an Object can consist of a Message_Seq, a Message_Seq followed by an Attach_Seq, or just an Attach_Seq.

TNEF_Stream:
TNEF_SIGNATURE Key Object
Key:
a nonzero 16-bit unsigned integer

TNEF enabled transports generate this value before using the TNEF implementation to generate a TNEF stream.

Object:
Message_Seq
Message_Seq Attach_Seq
Attach_Seq
Message_Seq:
attTnefVersion
attTnefVersion Msg_Attribute_Seq
attTnefVersion attMessageClass
attTnefVersion attMessageClass Msg_Attribute_Seq
attMessageClass
attMessageClass Msg_Attribute_Seq
Msg_Attribute_Seq
attTnefVersion:
LVL_MESSAGE attTnefVersion sizeof(ULONG) 0x00010000 checksum
attMessageClass:
LVL_MESSAGE attMessageClass msg_class_length msg_class checksum
Msg_Attribute_Seq:
Msg_Attribute
Msg_Attribute Msg_Attribute_Seq
Msg_Attribute:
LVL_MESSAGE attribute-ID attribute-length attribute-data checksum

Attribute-ID is one of the TNEF attribute identifiers, such as attSubject. Attribute-length is the length in bytes of the attribute data. Attribute-data is the data associated with the attribute.

Attach_Seq:
attRenddata
attRenddata Att_Attribute_Seq
attRenddata:
LVL_ATTACHMENT attRenddata sizeof(RENDDATA) renddata checksum

Renddata is the data associated with the RENDDATA structure containing the rendering information for the corresponding attachment. The RENDDATA structure is defined in the TNEF.H header file.

Att_Attribute_Seq:
Att_Attribute
Att_Attribute Att_Attribute_Seq
Att_Attribute:
LVL_ATTACHMENT attribute-ID attribute-length attribute-data checksum

Attribute-ID, attribute-length, and attribute-data have the same meanings as for the Msg_Attribute item.


Mapping of TNEF Attributes to MAPI Properties

The following table lists all the attributes defined in the TNEF implementation and their mappings to MAPI properties. In some cases, multiple MAPI properties are encoded as a single attribute. Some attributes have extended descriptions later in this appendix.

TNEF attribute | MAPI property or properties
attAidOwner | PR_OWNER_APPT_ID
attAttachCreateDate | PR_CREATION_TIME
attAttachData | PR_ATTACH_DATA_BIN or PR_ATTACH_DATA_OBJ
attAttachment | For information about this mapping, see Comments About the Attributes.
attAttachMetaFile | PR_ATTACH_RENDERING
attAttachModifyDate | PR_LAST_MODIFICATION_TIME
attAttachRenddata | PR_ATTACH_METHOD, PR_RENDERING_POSITION
attAttachTitle | PR_ATTACH_FILENAME
attAttachTransportFilename | PR_ATTACH_TRANSPORT_NAME
attBody | PR_BODY
attConversationID | PR_CONVERSATION_KEY See attConversationID and attParentID for details.
attDateEnd | PR_END_DATE See attDate Attributes for details.
attDateModified | PR_LAST_MODIFICATION_TIME See attDate Attributes for details.
attDateRecd | PR_MESSAGE_DELIVERY_TIME See attDate Attributes for details.
attDateSent | PR_CLIENT_SUBMIT_TIME See attDate Attributes for details.
attDateStart | PR_START_DATE See attDate Attributes for details.
attFrom | PR_SENDER_ENTRYID and PR_SENDER_NAME
attMAPIProps | For information about this attribute, see attMAPIProps.
attMessageClass | PR_MESSAGE_CLASS
attMessageID | PR_SEARCH_KEY See TNEF Correlation in X.400 Gateways and Transports.
attMessageStatus | PR_MESSAGE_FLAGS
attOriginalMessageClass | PR_ORIG_MESSAGE_CLASS
attOwner | See attOwner for details.
attParentID | PR_PARENT_KEY See attConversationID and attParentID for details.
attPriority | PR_PRIORITY
attRecipTable | PR_MESSAGE_RECIPIENTS
attRequestRes | PR_RESPONSE_REQUESTED
attSentFor | PR_SENT_REPRESENTING_ENTRYID
attSubject | PR_SUBJECT
attTnefVersion |


Comments About the Attributes

This section provides additional information about certain TNEF attributes. For more information about the MAPI properties that the attributes are mapped to, see the reference entries for the individual properties.


attMAPIProps

The attMAPIProps attribute is special in that it can be used to encode any MAPI property that does not have a counterpart in the set of existing TNEF-defined attributes. The attribute data is a counted set of MAPI properties laid end-to-end. The format of this encoding, which allows for any set of MAPI properties, is as follows:

Property_Seq:
property-count Property_Value, ...

There must be as many Property_Value items as the property-count value indicates.

Property_Value:
property-tag Property
property-tag Proptag_Name Property

The property-tag is simply the value associated with the property identifier, such as 0x0037001F for PR_SUBJECT.

Property:
Value
value-count Value, ...
Value:
value-data
value-size value-data padding
value-size value-IID value-data padding
Proptag_Name:
name-guid name-kind name-id
name-guid name-kind name-string-length name-string padding

The encapsulation of each property varies based on the property identifier and the property type. Property tags, identifiers, and types are defined in the MAPITAGS.H and MAPIDEFS.H header files.

If the property is a named property, then the property tag is immediately followed by the MAPI property name, consisting of a globally unique identifier (GUID), a type, and either an identifier or a Unicode string.

Multivalued properties and properties with variable length values, such as the PT_BINARY, PT_STRING8, PT_UNICODE, or PT_OBJECT property types, are treated in the following way. First the number of values, encoded as a 32-bit unsigned long, is placed in the TNEF stream, followed by the individual values. Each property's value-data is encoded as its size in bytes followed by the value-data itself. The value-data is padded out to a 4-byte boundary, although the amount of padding is not included in the value-size.

If the property is of type PT_OBJECT, the value-size is followed by the interface identifier of the object. The current implementation of TNEF only supports the IID_IMessage, IID_IStorage, and IID_Istream interface identifiers. The size of the interface identifier is included in the value-size.

If the object is an embedded message (that is, it has a property type of PT_OBJECT and an interface identifier of IID_Imessage), the value data is encoded as an embedded TNEF stream. The actual encoding of an embedded message in TNEF implementation is done by opening a second TNEF object for the original stream and processing the stream inline.


attDate Attributes

All MAPI properties relating to dates and times are mapped to TNEF attributes that have the attDate prefix. These are all encoded as DTR structures. The dates and times for attachment attributes are encoded as DTR structures as well.

A DTR structure is very similar to the SYSTEMTIME structure defined in the Win32 header files. The DTR structure is encoded in the TNEF stream as sizeof(DTR) bytes starting with the first member of the structure. The DTR structure is defined in the TNEF.H header file.


attOriginalMessageClass

A message class is stored as a string. The encoded string usually holds the MAPI-specified name of the message class. The exception is that to provide compatibility with Microsoft Mail for Windows for Workgroups 3.1, the following MAPI message classes are mapped to the following Microsoft Mail for Windows for Workgroups 3.1 message classes:

MAPI message class | Windows for Workgroups Mail 3.x
IPM | IPM.Microsoft Mail.Note
IPM.Note | IPM.Microsoft Mail.Note
IPM.Schedule.Meeting.Canceled | IPM.Microsoft Schedule.MtgCncl
IPM.Schedule.Meeting.Request | IPM.Microsoft Schedule.MtgReq
IPM.Schedule.Meeting.Resp.Neg | IPM.Microsoft Schedule.MtgRespN
IPM.Schedule.Meeting.Resp.Pos | IPM.Microsoft Schedule.MtgRespP
IPM.Schedule.Meeting.Resp.Tent | IPM.Microsoft Schedule.MtgRespA
Report.IPM.Note.NDR | IPM.Microsoft Mail.Non-Delivery
Report.IPM.Note.RN | IPM.Microsoft Mail.Read Receipt


attConversationID and attParentID

The Windows for Workgroups 3.1 Mail conversation key is a text string. The MAPI equivalent is a binary value. To provide backward compatability, the TNEF implementation converts the binary data to text and adds a terminating null character.


attFrom

The attFrom attribute is encoded as a TRP structure which encodes the display name and e-mail address of the sender, followed by the display name and address of the sender, followed by any necessary padding. The format for attFrom is as follows:

attFrom:
TRP-structure sender-display-name sender-address padding

The sender-display-name is a null-terminated string that is padded with an additional null character, if necessary, to reach a 2-byte boundary. The padding at the end of the attFrom encoding consists of as many null characters as needed to reach a sizeof(TRP) boundary.

TRP-structure:
trpidOneOff cbgrtrp cch cb

For the attFrom item, the TRP-structure is always a one-off encoding, so the trpid off the TRP-structure field is always trpidOneOff. The cbgrtrp, cch, and cb items correspond to the remaining fields of the TRP structure.

The cbgrtrp field is calculated as the sum of (sizeof(TRP) *2), the length of the null-terminated sender-display-name with its padding, and the length of the null-terminated sender-address.

The cch field is calculated as the length of the null-terminated display-name with its padding.

The cb field is calculated as the length of the null-terminated sender-address.

sender-address:
address-type : address '\0'

The sender-address is a string that is composed of four parts, the address-type, a literal colon (:), the address itself, and a terminating null character. For example, the string "fax:1-909-555-1234\0" would be a legal sender-address value.


attOwner

The attOwner attribute is encoded as counted strings laid end-to-end. The format for attOwner is as follows:

attOwner:
display-name-length display-name address-length email-address
email-address
type : address

Unlike other length values, the display-name-length and address-length are unsigned 16-bit values instead of unsigned long integers. They still include terminating null characters, however. The type and address strings in the email-address entry are separated by a literal colon (:) character, such as "smtp:joe@nowhere.com". Only the combined type:address string is null-terminated.

The mapping of MAPI properties to the attOwner attribute is dependent on the message class of the message being encoded. If the message is either a Microsoft Schedule+ meeting request or cancellation, then attOwner encodes one of the PR_SENT_REPRESENTING properties. If the message is a Microsoft Schedule+ meeting response of any type, then attOwner encodes one of the PR_RCVD_REPRESENTING properties.


attSentFor

The attSentFor attribute is encoded as counted strings laid end-to-end. The format for attSentFor is as follows:

attSentFor:
display-name-length display-name address-length email-address
email-address
type : address

Unlike other length values, the display-name-length and address-length are unsigned 16-bit values instead of unsigned long integers. They still include terminating null characters, however. The type and address strings in the email-address entry are separated by a literal colon (:) character, such as "smtp:joe@nowhere.com". Only the combined type:address string is null-terminated.


attRecipTable

When a recipient table is being encoded, each recipient is encoded as a row of MAPI properties. The format is as follows:

Row_Seq:
row-count Property_Sequence, ...

The format of Property_Seq is the same as in the attMAPIProps attribute.


attPriority

MAPI message priorities are also mapped to Microsoft Mail 3.1 priority values for backward compatability as follows:

Priority | MAPI value | TNEF value
normal | -1 | 3
high | 0 | 2
low | 1 | 1


attMessageStatus

MAPI message flags are mapped to Microsoft Mail 3.1 values to preserve backward compatability. All the flags are grouped together and encoded in a single byte. The mappings are as follows:

MAPI message flags | TNEF flags
MSGFLAG_READ | fmsRead
MSGFLAG_UNMODIFED | ~fmsModified
MSGFLAG_SUBMIT | fmsSubmitted
MSGFLAG_HASATTACH | fmsHasAttach
MSGFLAG_UNSENT | fmsLocal

These flags are defined in the TNEF.H header file.


attAttachRenddata

The attAttachRenddata attribute is encoded as a RENDDATA structure that describes how and where the attachment is rendered in the message text. The RENDDATA structure is simply encoded in the TNEF stream as sizeof(RENDDATA) bytes beginning with the first member of the RENDDATA structure. If the value of the RENDDATA structure's dwFlags member is set to MAC_BINARY, then the data for the following attachment is stored in MacBinary format; otherwise, the attachment data is encoded as usual.


OLE Attachments

Attachments that are OLE objects are encoded as OLE 1 stream objects for backward compatability with Microsoft Mail 3.x. If the original object is really an OLE 2 IStorage object, then the object must be converted to an OLE 1 stream. This conversion is performed using the OleConvertIStorageToOLESTREAM function, which is part of the Win32 OLE libraries; examples of this conversion can be found in the OLE Programmer's Reference.


TNEF Correlation

Some messaging systems perform a correlation check on any TNEF stream attached to an inbound message to verify that the TNEF stream does in fact belong to that message. This involves matching the value of some field in the header of the inbound message with a copy of that value stored in some property in the TNEF stream. Values that are presumably unique for each message, such as message ID numbers, are typically used for this. The transport or gateway the created the TNEF stream is responsible for choosing an appropriate value from the message header and placing a copy into an appropriate property before encoding the outgoing message's properties into the TNEF stream. Gateways or transports that receive the message can then extract that property from the TNEF stream and verify that its value matches the value of the corresponding header field on the inbound message.

If the values do not match, the gateway or transport should discard the TNEF stream and process only the native message envelope. Such checks are prudent because non-MAPI-based mail clients may attach a file containing a TNEF stream from an old message to a forwarding or even an unrelated message; if not checked, such an error may result in the loss of message text.

The header field value chosen must be unique to the message. There is no fixed header field for all messaging systems because different messaging systems use different header fields, but typically the messaging system assigns a unique identifier to the message which is suitable for this purpose. For example, SMTP systems typically use the MessageID header, while X.400 systems typically use the IM_THIS_IPM attribute.


TNEF Correlation in SMTP Gateways and Transports

Gateways and transports that connect to internet based systems, those that use SMTP, use the value of the MessageID SMTP header and the PR_TNEF_CORRELATION_KEY property to implement TNEF correlation.

The value of the MessageID header of the outbound message should be copied to the PR_TNEF_CORRELATION_KEY property and encoded in the attMAPIProps attribute of the TNEF stream. Note that PR_TNEF_CORRELATION_KEY is a binary property, while the MessageID is a string; the null terminator should be included in the copy and in the comparison.

This technique is used by all Microsoft software that connects MAPI-based messaging systems to the Internet, such as Microsoft Mail 3.x and Microsoft Exchange Server. This technique should be used by any SMTP gateways and transports that connect to systems that support MAPI clients in order to maximize interoperability.


TNEF Correlation in X.400 Gateways and Transports

Gateways and transports that connect to X.400-based systems, use the value of the IM_THIS_IPM X.400 attribute and the attMessageID TNEF attribute to implement TNEF correlation.

The value of the IM_THIS_IPM attribute of the outbound message is copied to attMessageID in the TNEF stream. The IM_THIS_IPM X.400 attribute is typically a string, while the attMessageID TNEF attribute is a string of hexadecimal digits representing a binary value. Therefore, each character in the IM_THIS_IPM X.400 attribute, including the terminating null character, must be converted to a 2-character hexadecimal string representing the ASCII value of that character. For instance, if the IM_THIS_IPM X.400 attribute is the following string:

3030322D3030312D305337533A3A3936303631312D313533373030

then the value of attMessageID would be the following sequence of hexadecimal digits:

33 30 33 30 33 32 32 44

33 30 33 30 33 31 32 44

33 30 35 33 33 37 35 33

33 41 33 41 33 39 33 36

33 30 33 36 33 31 33 31

32 44 33 31 33 35 33 33

33 37 33 30 33 30 00

This technique is used by the Microsoft Exchange Server X.400 Connector. This technique should be used by any X.400 gateways and transports that connect to Microsoft Exchange Server in order to maximize interoperability.

For greatest compatibility with future as well as present Microsoft software, the IM_THIS_IPM X.400 attribute should also be copied to the PR_TNEF_CORRELATION_KEY property. However, since PR_TNEF_CORRELATION_KEY is a binary property, no translation into a hexadecimal string is necessary.


Mapping of X.400 P2 Attributes to MAPI Properties

The X/Open CAE Specification API to Electronic Mail (X.400), published by the X/Open Company Limited and X.400 API Association (1991), describes a recommended implementation of the X.400 (1984) and X.400 (1988) Blue Book specifications.

This appendix describes mappings between the recommended implementation's P2 attributes and MAPI properties.

The reference information is presented in two different ways in this appendix:

  • X.400 attributes are organized by object.
  • All X.400 attributes are combined into one comprehensive list and presented in alphabetical order.


X.400 Attributes By Object

The following entries contain tables for each object listing the mappings from X.400 P2 attributes to their corresponding MAPI properties.


OMP_O_IM_C_BD_PRT

The class OMP_O_IM_C_BD_PRT does not have any attributes that are unique to the class.


OMP_O_IM_C_BILAT_DEF_BD_PRT

The attributes of the class OMP_O_IM_C_BILAT_DEF_BD_PRT map to MAPI properties as follows:

MH ID/Type | MAPI Property
IM_BILATERAL_DATA | PR_ATTACH_DATA_BIN


OMP_O_IM_C_EXTERN_DEF_BD_PRT

The attributes of the class OMP_O_IM_C_EXTERN_DEF_BD_PRT map to MAPI properties as follows:

MH ID/Type | MAPI Property
IM_EXTERNAL_DATA | PR_ATTACH_DATA_BIN, PR_ATTACH_FILENAME, PR_ATTACH_TAG
IM_ EXTERNAL_PARAMETERS | PR_ATTACHMENT_X400_PARAMETERS


OMP_O_IM_C_G3_FAX_BD_PRT

The attributes of the class OMP_O_IM_C_G3_FAX_BD_PRT are not mapped to MAPI properties.

MH ID/Type | MAPI Property
IM_G3_FAX_NBPS | Not mapped to a MAPI property.
IM_IMAGES | Not mapped to a MAPI property.


OMP_O_IM_C_G4_CLASS_1_BD_PRT

The attributes of the class OMP_O_IM_C_G4_CLASS_1_BD_PRT are not mapped to MAPI properties.

MH ID/Type | MAPI Property
IM_G4_CLASS_1_DOCUMENT | Not mapped to a MAPI property.


OMP_O_IM_C_GENERAL_TEXT_BD_PRT

The attributes of the class OMP_O_IM_C_GENERAL_TEXT_BD_PRT are not mapped to MAPI properties.

MH ID/Type | MAPI Property
IM_CHAR_SET_REG | Not mapped to a MAPI property.
IM_TEXT | Not mapped to a MAPI property.


OMP_O_IM_C_IA5_TEXT_BD_PRT

The attributes of the class OMP_O_IM_C_IA5_TEXT_BD_PRT are mapped to the following MAPI properties:

MH ID/Type | MAPI Property
IM_REPERTOIRE | Not mapped to a MAPI property.
IM_TEXT | PR_BODY


OMP_O_IM_C_INTERPERSONAL_MSG

The attributes of the class OMP_O_IM_C_INTERPERSONAL_MSG map to MAPI properties as follows:

MH ID/Type | MAPI Property
IM_AUTHORIZING_USERS | PR_AUTHORIZING_USERS
IM_AUTO_FORWARDED | PR_AUTO_FORWARDED
IM_BLIND_COPY_RECIPIENTS | PR_DISPLAY_BCC
IM_BODY | PR_BODY
IM_COPY_RECIPIENTS | PR_DISPLAY_CC
IM_EXPIRY_TIME | PR_EXPIRY_TIME
IM_IMPORTANCE | PR_IMPORTANCE
IM_INCOMPLETE_COPY | PR_INCOMPLETE_COPY
IM_LANGUAGES | PR_LANGUAGES
IM_OBSOLETED_IPMS | PR_OBSOLETED_IPMS
IM_ORIGINATOR | PR_CALLBACK_TELEPHONE_NUMBER, PR_SENDER_ADDRTYPE, PR_SENDER_EMAIL_ADDRESS, PR_SENDER_ENTRYID, PR_SENDER_NAME, PR_SENDER_SEARCH_KEY (and all PR_SENT_REPRESENTING_* properties)
IM_PRIMARY_RECIPIENTS | PR_DISPLAY_TO
IM_RELATED_IPMS | PR_RELATED_IPMS
IM_REPLIED_TO_IPM | PR_PARENT_KEY
IM_REPLY_RECIPIENTS | PR_REPLY_RECIPIENT_ENTRIES, PR_REPLY_RECIPIENT_NAMES
IM_REPLY_TIME | PR_REPLY_TIME
IM_SENSITIVITY | PR_SENSITIVITY
IM_SUBJECT | PR_NORMALIZED_SUBJECT, PR_SUBJECT, PR_SUBJECT_PREFIX
IM_THIS_IPM | PR_SEARCH_KEY

The following constant values are mapped from IM_IMPORTANCE to PR_IMPORTANCE:

Importance | MAPI value
IM_HIGH | 2
IM_LOW | 0
IM_ROUTINE | 1

The following constant values are mapped from IM_SENSITIVITY to PR_SENSITIVITY:

IM_SENSITIVITY value | PR_SENSITIVITY value
IM_COMPANY_CONFIDENTIAL | SENSITIVITY_COMPANY_CONFIDENTIAL
IM_NOT_SENSITIVE | SENSITIVITY_NONE
IM_PERSONAL | SENSITIVITY_PERSONAL
IM_PRIVATE | SENSITIVITY_PRIVATE


OMP_O_IM_C_INTERPERSONAL_NOTIF

The attributes of the class OMP_O_IM_C_INTERPERSONAL_NOTIF map to MAPI properties as follows:

MH ID/Type | MAPI Property
IM_CONVERSION_EITS | PR_CONVERSION_EITS
IM_IPM_INTENDED_RECIPIENT | PR_ORIGINALLY_INTENDED_RECIPIENT_NAME
IM_IPN_ORIGINATOR | PR_CALLBACK_TELEPHONE_NUMBER, PR_SENDER_ADDRTYPE, PR_SENDER_EMAIL_ADDRESS, PR_SENDER_ENTRYID, PR_SENDER_NAME, PR_SENDER_SEARCH_KEY (and all PR_SENT_REPRESENTING_ * properties)
IM_SUBJECT_IPM | PR_ORIGINAL_SEARCH_KEY


OMP_O_IM_C_IPM_IDENTIFIER

The attributes of the class OMP_O_IM_C_IPM_IDENTIFIER map to MAPI properties as follows:

MH ID/Type | MAPI Property
IM_USER, IM_USER_RELATIVE_IDENTIFIER | Construct a GUID from IM_USER_RELATIVE_IDENTIFIER


OMP_O_IM_C_ISO_6937_TEXT_BD_PRT

The attributes of the class OMP_O_IM_C_ISO_6937_TEXT_BD_PRT are mapped to the following MAPI properties:

MH ID/Type | MAPI Property
IM_REPERTOIRE | Not mapped to a MAPI property.
IM_TEXT | PR_ATTACH_DATA_BIN


OMP_O_IM_C_MESSAGE_BD_PRT

The attributes of the class OMP_O_IM_C_MESSAGE_BD_PRT are mapped as follows:

MH ID/Type | MAPI Property
IM_ENVELOPE | Not mapped to a MAPI property.
IM_IPM | Mapped to an IMessage object embedded in the message.


OMP_O_IM_C_MIXED_MODE_BD_PRT

The attributes of the class OMP_O_IM_C_MIXED_MODE_BD_PRT are not mapped to any MAPI properties.

MH ID/Type | MAPI Property
IM_MIXED_MODE_DOCUMENT | Not mapped to a MAPI property.


OMP_O_IM_C_NATIONAL_DEF_BD_PRT

The attributes of the class OMP_O_IM_C_NATIONAL_DEF_BD_PRT are not mapped to MAPI properties.

MH ID/Type | MAPI Property
IM_NATIONAL_DATA | Not mapped to a MAPI property.


OMP_O_IM_C_NON_RECEIPT_NOTIF

The attributes of the class OMP_O_IM_C_NON_RECEIPT_NOTIF map to MAPI properties (when PR_NON_RECEIPT_NOTIFICATION_REQUESTED = 1 in Recipient table or when the message has PR_READ_RECEIPT_REQUESTED = 1), as follows:

MH ID/Type | MAPI Property
IM_AUTO_FORWARD_COMMENT | PR_AUTO_FORWARD_COMMENT
IM_DISCARD_REASON | PR_DISCARD_REASON
IM_NON_RECEIPT_REASON | PR_NON_RECEIPT_REASON
IM_RETURNED_IPM | (Object; no corresponding property)

The following constant values are mapped from IM_DISCARD_REASON to PR_DISCARD_REASON:

IM_DISCARD_REASON value | PR_DISCARD_REASON value
IM_NO_DISCARD | -1
IM_IPM_EXPIRED | 0
IM_IPM_OBSOLETED | 1
IM_USER_TERMINATED | 2

The following constant values are mapped from IM_NON_RECEIPT_REASON to PR_NON_RECEIPT_REASON:

IM_NON_RECEIPT_REASON value | PR_NON_RECEIPT_REASON value
IM_IPM_AUTO_FORWARDED | 1
IM_IPM_DISCARDED | 0


OMP_O_IM_C_ODA_BD_PRT

The attributes of the class OMP_O_IM_C_ODA_BD_PRT are not mapped to MAPI properties.

MH ID/Type | MAPI Property
IM_APPLICATION_PROFILE | Not mapped to a MAPI property.
IM_ARCHITECTURE_CLASS | Not mapped to a MAPI property.
IM_ODA_DOCUMENT | Not mapped to a MAPI property.


OMP_O_IM_C_OR_DESCRIPTOR

The attributes of the class OMP_O_IM_C_OR_DESCRIPTOR map to MAPI properties as follows:

MH ID/Type | MAPI Property
IM_FORMAL_NAME | Extract name using PR_ENTRYID; for X.400 address types, build an OR Address from string address.
IM_FREE_FORM_NAME | PR_SENDER_NAME for originator, PR_DISPLAY_NAME for recipient, or extract the display name using PR_SENDER_ENTRYID
IM_TELEPHONE_NUMBER | PR_CALLBACK_TELEPHONE_NUMBER for originator, PR_PRIMARY_TELEPHONE_NUMBER for recipient


OMP_O_IM_C_RECEIPT_NOTIF

The attributes of the class OMP_O_IM_C_RECEIPT_NOTIF map to MAPI properties, as follows:

MH ID/Type | MAPI Property
IM_ACKNOWLEDGEMENT_MODE | PR_ACKNOWLEDGEMENT_MODE
IM_RECEIPT_TIME | PR_RECEIPT_TIME
IM_SUPPLEMENTARY_RECEIPT_INFO | PR_REPORT_TEXT

The following constant values are mapped from IM_ACKNOWLEDGEMENT_MODE to PR_ACKNOWLEDGEMENT_MODE:

IM_ACKNOWLEDGEMENT_ MODE value | PR_ACKNOWLEDGEMENT_ MODE value
IM_AUTOMATIC | 1
IM_MANUAL | 0


OMP_O_IM_C_RECIPIENT_SPECIFIER

The attributes of the class OMP_O_IM_C_OR_DESCRIPTOR map to MAPI properties as follows:

MH ID/Type | MAPI Property
IM_IPM_RETURN_REQUESTED | PR_IPM_RETURN_REQUESTED
IM_NOTIFICATION_REQUEST | PR_NON_RECEIPT_NOTIFICATION_ REQUESTED, PR_READ_RECEIPT_REQUESTED
IM_RECIPIENT | PR_ADDRTYPE, PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_ENTRYID, PR_OFFICE_LOCATION, PR_PRIMARY_TELEPHONE_NUMBER, PR_SEARCH_KEY
IM_REPLY_REQUESTED | PR_REPLY_REQUESTED

The following constant values are mapped from IM_NOTIFICATION_REQUEST to the corresponding MAPI properties:

IM_NOTIFICATION_REQUEST Value | MAPI Values
IM_ALWAYS | PR_NON_RECEIPT_NOTIFICATION_ REQUESTED = TRUE, PR_READ_RECEIPT_REQUESTED = TRUE
IM_NEVER | PR_NON_RECEIPT_NOTIFICATION_ REQUESTED = FALSE, PR_READ_RECEIPT_REQUESTED = FALSE
IM_NON_RECEIPT | PR_NON_RECEIPT_NOTIFICATION_ REQUESTED = TRUE, PR_READ_RECEIPT_REQUESTED = FALSE


OMP_O_IM_C_TELETEX_BD_PRT

The attributes of the class OMP_O_IM_C_TELETEX_BD_PRT are mapped to the following MAPI properties:

MH ID/Type | MAPI Property
IM_TELETEX_COMPATIBLE | Not mapped to a MAPI property.
IM_TELETEX_DOCUMENT | PR_BODY
IM_TELETEX_NBPS | Not mapped to a MAPI property.


OMP_O_IM_C_UNIDENTIFIED_BD_PRT

The attributes of the class OMP_O_IM_C_UNIDENTIFIED_BD_PRT are not mapped to MAPI properties.

MH ID/Type | MAPI Property
IM_UNIDENTIFIED_DATA | Not mapped to a MAPI property.
IM_UNIDENTIFIED_TAG | Not mapped to a MAPI property.


OMP_O_IM_C_USA_NAT_DEF_BD_PRT

The attributes of the class OMP_O_IM_C_USA_NAT_DEF_BD_PRT are mapped to the following MAPI properties:

MH ID/Type | MAPI Property
IM_BODY_PART_NUMBER | Not mapped to a MAPI property.
IM_USA_DATA | Not mapped to a MAPI property.


OMP_O_IM_C_VIDEOTEX_BD_PRT

The attributes of the class OMP_O_IM_C_VIDEOTEX_BD_PRT are not mapped to MAPI properties.

MH ID/Type | MAPI Property
IM_VIDEOTEX_DATA | Not mapped to a MAPI property.
IM_VIDEOTEX_SYNTAX | Not mapped to a MAPI property.


Comprehensive X.400 Attributes Reference

The following table contains mappings between X.400 P2 attributes and MAPI properties, listed in alphabetical order. The name of the object appears in parentheses.

MH ID/Type | MAPI Property
IM_ACKNOWLEDGEMENT_MODE (OMP_O_IM_C_RECEIPT_NOTIF) | PR_ACKNOWLEDGEMENT_MODE
IM_APPLICATION_PROFILE (OMP_O_IM_C_ODA_BD_PRT) | Not mapped to a MAPI property.
IM_ARCHITECTURE_CLASS (OMP_O_IM_C_ODA_BD_PRT) | Not mapped to a MAPI property.
IM_AUTHORIZING_USERS (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_AUTHORIZING_USERS
IM_AUTO_FORWARD_COMMENT (OMP_O_IM_C_NON_RECEIPT_NOTIF) | PR_AUTO_FORWARD_COMMENT
IM_AUTO_FORWARDED (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_AUTO_FORWARDED
IM_BILATERAL_DATA (OMP_O_IM_C_BILAT_DEF_BD_PRT) | PR_ATTACH_DATA_BIN
IM_BLIND_COPY_RECIPIENTS (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_DISPLAY_BCC
IM_BODY (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_BODY
IM_BODY_PART_NUMBER (OMP_O_IM_C_USA_NAT_DEF_BD_PRT) | Not mapped to a MAPI property.
IM_CHAR_SET_REG (OMP_O_IM_C_GENERAL_TEXT_BD_PRT) | Not mapped to a MAPI property.
IM_CONVERSION_EITS (OMP_O_IM_C_INTERPERSONAL_NOTIF) | PR_CONVERSION_EITS
IM_COPY_RECIPIENTS (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_DISPLAY_CC
IM_DISCARD_REASON (OMP_O_IM_C_NON_RECEIPT_NOTIF) | PR_DISCARD_REASON
IM_ENVELOPE (OMP_O_IM_C_MESSAGE_BD_PRT) | Not mapped to a MAPI property.
IM_EXPIRY_TIME (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_EXPIRY_TIME
IM_EXTERNAL_DATA (OMP_O_IM_C_EXTERN_DEF_BD_PRT) | PR_ATTACH_DATA_BIN, PR_ATTACH_FILENAME, PR_ATTACH_TAG
IM_EXTERNAL_PARAMETERS (OMP_O_IM_C_EXTERN_DEF_BD_PRT) | PR_ATTACHMENT_X400_PARAMETERS
IM_FORMAL_NAME (OMP_O_IM_C_OR_DESCRIPTOR) | Extract name using PR_ENTRYID; for X.400 address types, build an OR Address from string address.
IM_FREE_FORM_NAME (OMP_O_IM_C_OR_DESCRIPTOR) | PR_SENDER_NAME for originator, PR_DISPLAY_NAME for recipient, or extract the display name using PR_SENDER_ENTRYID
IM_G3_FAX_NBPS (OMP_O_IM_C_G3_FAX_BD_PRT) | Not mapped to a MAPI property.
IM_G4_CLASS_1_DOCUMENT (OMP_O_IM_C_G4_CLASS_1_BD_PRT) | Not mapped to a MAPI property.
IM_IMAGES (OMP_O_IM_C_G3_FAX_BD_PRT) | Not mapped to a MAPI property.
IM_IMPORTANCE (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_IMPORTANCE
IM_INCOMPLETE_COPY (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_INCOMPLETE_COPY
IM_IPM (OMP_O_IM_C_MESSAGE_BD_PRT) | Mapped to an IMessageobject embedded in the message.
IM_IPM_INTENDED_RECIPIENT (OMP_O_IM_C_INTERPERSONAL_NOTIF) | PR_ORIGINALLY_INTENDED_RECIPIENT_NAME
IM_IPM_RETURN_REQUESTED (OMP_O_IM_C_OR_DESCRIPTOR) | PR_IPM_RETURN_REQUESTED
IM_IPN_ORIGINATOR (OMP_O_IM_C_INTERPERSONAL_NOTIF) | PR_CALLBACK_TELEPHONE_NUMBER, PR_SENDER_ADDRTYPE, PR_SENDER_EMAIL_ADDRESS, PR_SENDER_ENTRYID, PR_SENDER_NAME, PR_SENDER_SEARCH_KEY (and all PR_SENT_REPRESENTING_ * properties)
IM_LANGUAGES (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_LANGUAGES
IM_MIXED_MODE_DOCUMENT (OMP_O_IM_C_MIXED_MODE_BD_PRT) | Not mapped to a MAPI property.
IM_NATIONAL_DATA (OMP_O_IM_C_NATIONAL_DEF_BD_PRT) | Not mapped to a MAPI property.
IM_NON_RECEIPT_REASON (OMP_O_IM_C_NON_RECEIPT_NOTIF) | PR_NON_RECEIPT_REASON
IM_NOTIFICATION_REQUEST (OMP_O_IM_C_OR_DESCRIPTOR) | PR_NON_RECEIPT_NOTIFICATION_REQUESTED, PR_READ_RECEIPT_REQUESTED
IM_OBSOLETED_IPMS (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_OBSOLETED_IPMS
IM_ODA_DOCUMENT (OMP_O_IM_C_ODA_BD_PRT) | Not mapped to a MAPI property.
IM_ORIGINATOR (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_CALLBACK_TELEPHONE_NUMBER, PR_SENDER_ADDRTYPE, PR_SENDER_EMAIL_ADDRESS, PR_SENDER_ENTRYID, PR_SENDER_NAME, PR_SENDER_SEARCH_KEY (and all PR_SENT_REPRESENTING_* properties)
IM_PRIMARY_RECIPIENTS (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_DISPLAY_TO
IM_RECEIPT_TIME (OMP_O_IM_C_RECEIPT_NOTIF) | PR_RECEIPT_TIME
IM_RECIPIENT (OMP_O_IM_C_OR_DESCRIPTOR) | PR_ADDRTYPE, PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_ENTRYID, PR_OFFICE_LOCATION, PR_PRIMARY_TELEPHONE_NUMBER, PR_SEARCH_KEY
IM_RELATED_IPMS (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_RELATED_IPMS
IM_REPERTOIRE (OMP_O_IM_C_IA5_TEXT_BD_PRT) | Not mapped to a MAPI property.
IM_REPERTOIRE (OMP_O_IM_C_ISO_6937_TEXT_BD_PRT) | Not mapped to a MAPI property.
IM_REPLIED_TO_IPM (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_PARENT_KEY
IM_REPLY_RECIPIENTS (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_REPLY_RECIPIENT_ENTRIES, PR_REPLY_RECIPIENT_NAMES
IM_REPLY_REQUESTED (OMP_O_IM_C_OR_DESCRIPTOR) | PR_REPLY_REQUESTED
IM_REPLY_TIME (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_REPLY_TIME
IM_RETURNED_IPM (OMP_O_IM_C_NON_RECEIPT_NOTIF) | (Object; no corresponding property)
IM_SENSITIVITY (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_SENSITIVITY
IM_SUBJECT (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_NORMALIZED_SUBJECT, PR_SUBJECT, PR_SUBJECT_PREFIX
IM_SUBJECT_IPM (OMP_O_IM_C_INTERPERSONAL_NOTIF) | PR_ORIGINAL_SEARCH_KEY
IM_SUPPLEMENTARY_RECEIPT_INFO (OMP_O_IM_C_RECEIPT_NOTIF) | PR_REPORT_TEXT
IM_TELEPHONE_NUMBER (OMP_O_IM_C_OR_DESCRIPTOR) | PR_CALLBACK_TELEPHONE_NUMBER for Originator, PR_PRIMARY_TELEPHONE_NUMBER for Recipient
IM_TELETEX_COMPATIBLE (OMP_O_IM_C_TELETEX_BD_PRT) | Not mapped to a MAPI property.
IM_TELETEX_DOCUMENT (OMP_O_IM_C_TELETEX_BD_PRT) | PR_BODY
IM_TELETEX_NBPS (OMP_O_IM_C_TELETEX_BD_PRT) | Not mapped to a MAPI property.
IM_TEXT (OMP_O_IM_C_GENERAL_TEXT_BD_PRT) | Not mapped to a MAPI property.
IM_TEXT (OMP_O_IM_C_IA5_TEXT_BD_PRT) | PR_BODY
IM_TEXT (OMP_O_IM_C_ISO_6937_TEXT_BD_PRT) | PR_ATTACH_DATA_BIN
IM_THIS_IPM (OMP_O_IM_C_INTERPERSONAL_MSG) | PR_SEARCH_KEY
IM_UNIDENTIFIED_DATA (OMP_O_IM_C_UNIDENTIFIED_BD_PRT) | Not mapped to a MAPI property.
IM_UNIDENTIFIED_TAG (OMP_O_IM_C_UNIDENTIFIED_BD_PRT) | Not mapped to a MAPI property.
IM_USA_DATA (OMP_O_IM_C_USA_NAT_DEF_BD_PRT) | Not mapped to a MAPI property.
IM_USER, IM_USER_RELATIVE_IDENTIFIER (OMP_O_IM_C_IPM_IDENTIFIER) | Construct a GUID from IM_USER_RELATIVE_IDENTIFIER
IM_VIDEOTEX_DATA (OMP_O_IM_C_VIDEOTEX_BD_PRT) | Not mapped to a MAPI property.
IM_VIDEOTEX_SYNTAX (OMP_O_IM_C_VIDEOTEX_BD_PRT) | Not mapped to a MAPI property.


Mapping of Internet Mail Attributes to MAPI Properties

This appendix describes how a MAPI transport provider or MAPI-aware gateway which connects to the Internet should translate between MAPI message properties and Simple Mail Transport Protocol (SMTP) message attributes. SMTP is the messaging protocol used on much of the Internet. SMTP defines a set of message headers — the message envelope — and a message content format. SMTP is fully documented in a set of two docments, RFC 821 and RFC 822, which can be found at a number of FTP and WWW sites on the Internet.

For information on the SMTP protocol used to communicate with SMTP-based mail agents, see RFC 821.

For addressing and standard message headers, see RFC 822.

For MIME, see RFC 1521.

The goal of mapping SMTP message attributes to MAPI properties (and vice versa) is to ensure that the full content of MAPI messages, over and above that which can be encoded using native SMTP message attributes, can be reliably exchanged among different MAPI components that must communicate over the Internet. This document is based on work already done on such components at Microsoft. How to translate between MAPI message properties and X.400 message attributes is described in the appendix, Mapping of X.400 P2 Attributes to MAPI Properties.

This document assumes familiarity with MAPI transports, TNEF, and SMTP mail. It strives to be concise rather than abundantly clear.

As a convention, "outbound" refers to mail traveling from a MAPI-compliant UA or MTA to the Internet, and "inbound" refers to mail traveling from the Internet to a MAPI component.


Addressing

The format of SMTP e-mail addresses is defined in RFC 822. MAPI components should handle any address that complies with that standard. However, there is a particular form of RFC 822 address that best encodes MAPI addresses:

display-name <email-address>

The angle brackets are included as literals. Blanks are common in display names; they need not be quoted. A typical address might look like this one, which belongs to one of the coauthors of RFC 1521:

Nathaniel Borenstein <nsb@bellcore.com>

If the display name contains characters that have special meaning in SMTP addresses, such as < or @, the entire display name should be quoted using double quotes. On outbound mail, if the total length of the e-mail address plus display name exceeds 255 characters, the display name should be dropped.

The parts of an SMTP address map into MAPI properties as follows:

SMTP address component | MAPI property
display-name for all recipients | PR_DISPLAY_NAME
display-name for From field | PR_SENDER_NAME
display-name for Sender field | PR_SENT_REPRESENTING_NAME
email-address | PR_EMAIL_ADDRESS
implicit, always "SMTP" | PR_ADDRTYPE

If there is no display name for an address on inbound mail, the entire e-mail address should be used instead. The address type is always SMTP.

Recipient properties are taken from the MAPI message's recipient table; sender properties are taken from the message itself.


Message Envelope

RFC 822 headers are mapped to MAPI properties as follows. PR_SENDER_* is an abbreviation for the following 5 properties:

PR_SENDER_NAME

PR_SENDER_ADDRTYPE

PR_SENDER_EMAIL_ADDRESS

PR_SENDER_SEARCH_KEY

PR_SENDER_ENTRYID

Similar abbreviations are used for PR_SENT_REPRESENTING_* and other groups of message properties.

SMTP header | MAPI property
From: | Outbound: PR_SENDER_*; inbound: PR_SENDER_* and PR_SENT_REPRESENTING_*
Date: | Outbound: current time; inbound: PR_MESSAGE_DELIVERY_TIME
To: | PR_DISPLAY_NAME and PR_EMAIL_ADDRESS for recipients where PR_RECIPIENT_TYPE is MAPI_TO
Cc: | PR_DISPLAY_NAME and PR_EMAIL_ADDRESS for recipients where PR_RECIPIENT_TYPE is MAPI_CC
Bcc: | PR_DISPLAY_NAME and PR_EMAIL_ADDRESS for recipients where PR_RECIPIENT_TYPE is MAPI_BCC
Received: | No corresponding MAPI property; put local host name and your component name here
Return-receipt-to: | PR_REPORT_NAME and PR_REPORT_ENTRYID
Reply-to: | PR_REPLY_RECIPIENT_ENTRIES and PR_REPLY_RECIPIENT_NAMES
Subject: | PR_SUBJECT No particular length limitation.
MIME-version: | Always "1.0"
X-MS-Attachment: | For compatibility with MS Mail SMTP gateway. filename size mm-dd-yyy hh:mm Details below.
entire SMTP message envelope | PR_TRANSPORT_MESSAGE_HEADERS
header name TBD | PR_SEND_RICH_INFO for sender only. The TBD header should be used to determine whether the sender is capable of interpreting TNEF content in a reply.
MessageID: | PR_TNEF_CORRELATION_KEY
Content-type | Either text/plain or multipart/mixed. See "Message Content" section.

The X-MS-Attachment header is formatted as four tokens, separated by a space:

name size date time

The first token is the filename, which may contain embedded spaces, so this header should be parsed from the right on inbound messages. The size is in bytes; the date is formatted as mm-dd-yyyy, and the time as hh:mm.

Note MessageID is not mapped to PR_SEARCH_KEY because the SMTP domain has specific requirements on the format of the message identifier which make it impossible to encode an arbitrary MAPI message identifier. Instead, MessageID is mapped to PR_TNEF_CORRELATION_KEY. This property is a transport-defined property that is set by the transport sending an outbound message and used by a transport receiving an inbound message. For more information, see Developing a TNEF-Enabled Transport Provider.


Message Content

There are two possible encodings for the message content: one using MIME, the other using uuencode. MIME is the preferred encoding. In addition, MAPI defines a per-recipient property, PR_SEND_RICH_INFO, that governs whether or not TNEF information should be included in an outgoing message. So there are a total of four ways of encoding message content:

  • MIME with TNEF
  • MIME without TNEF
  • uuencode with TNEF
  • uuencode without TNEF

How to choose MIME or uuencode for outbound messages is not specified.

The following properties are excluded from TNEF: PR_SENDER_*, PR_ATTACH_DATA_*, PR_BODY. All other transmittable message properties are included in the TNEF stream.


Message Text

For outbound messages in MIME mode, the content-type depends on whether there are attachments and what the message text looks like. If there are attachments, the Content-type is multipart/mixed; the message text and each attachment become a separate part of the message content, each with its own content-type. If there are no attachments, the content-type of the message is text/plain and there is only one part.

The message text is not line-wrapped unless some line exceeds 140 characters in length. If one does, the entire text is wrapped to 76 columns and the quoted-printable encoding is used to preserve line breaks. The content-type depends on what characters are found in the message text, as follows:

  • If only 7-bit characters are found and no line exceeds 140 characters in length, the message is ASCII text.

    Content-type: text/plain; charset=us-ascii
    (Content-Transfer-Encoding=7bit is assumed.)

  • If long lines or 8-bit characters are found, the message is text and the character set is determined by the locale. It should be chosen from the character sets defined by ISO standard 8859.

    Content-type: text/plain; charset=iso-8859-1 (or another valid charset)
    Content-Transfer-Encoding: quoted-printable

For inbound MIME messages, if the first message content part has Content-type: text/* (that is, any text type) and its character set is recognized, it is mapped to PR_BODY. A first message content part not meeting this criterion becomes an attachment. Any subsequent parts also become attachments.

In uuencode mode, message text in outbound messages is line-wrapped to 78 columns, as for MS Mail 3.x. The content-type is "text/plain." To preserve the original message's paragraph breaks under these circumstances, observe the following conventions in the wrapped text. There are three possible reasons for ending a line of text, each with its own character sequence:

  • Line-break. The original text contained a newline entered by the user (paragraph mark). In the transport, this maps to a newline with no preceding blanks. If the user enters a newline preceded by blanks, the blanks should be stripped out.
  • Line-nobreak. The original text contained a word too long to fit on a single line of the message. In the transport, this maps to a newline preceded by two blanks.
  • Line-wrap. The original text contained no newline, the text is too long to fit on a single line of the message, but it can be broken between two words. In the transport, this maps to a newline preceded by a single blank.


Attached Files and Messages

If MIME with TNEF is used while encoding message content, all attachment properties and content are in the TNEF stream. The TNEF itself is a single, binary attached file named WINMAIL.DAT, encoded as described for MIME without TNEF.

If MIME is used without TNEF, attached files are sent as MIME message content parts. The filename is placed in the name parameter to the Content-type header for the attachment. The character set for the attachment is placed in the charset parameter to the Content-type; it and the content-transfer-encoding are determined by scanning the entire attachment content. URL attachments are treated specially:

  • If the attachment is a URL (an attached file with extension .URL), and the access mode defined in it is anonymous FTP, it is encoded as an external message, and the content of the file (the URL) is copied into the header of the external message.

    Content-type: message/external-body; access-type=anon-ftp
    (Content-Transfer-Encoding: 7bit is assumed.)

  • If only 7-bit characters are found and no line exceeds 140 characters in length, the attachment is ASCII text.

    Content-type: text/plain; charset=us-ascii
    Content-Transfer-Encoding: 7bit

  • If long lines or up to 25% 8-bit characters are found, the attachment content is text and the character set is determined by the locale. It should be chosen from the character sets defined by ISO standard 8859.

    Content-type: text/plain; charset=ISO-8859-1 (or what have you)
    Content-Transfer-Encoding: quoted-printable

  • If 25% or more of the characters have the high bit set, the attachment is binary. It is encoded using the Base64 algorithm.

    Content-type: application/octet-stream (by default; based on file extension)
    Content-Transfer-Encoding: base64

On outbound messages, the content-type should be derived from the filename's three-letter extension. This mapping exists in the system registry; under there is a string value named "Content Type" that gives the MIME content type if one is defined. This example is for a TIFF image file:

HKEY_LOCAL_MACHINE\
Software\
Microsoft\
Classes\
.tif
Content Type = "image/tiff"

If there is no mapping for the file extension, the default application/octet-stream should be used. Windows 95 now supports this system registry mapping. Windows NT will support it in a forthcoming release. Windows 3.x does not support a system registry; implementations are free to choose how they store this mapping.

On inbound messages, the content-type for an attachment should always be copied to the MAPI property PR_ATTACH_MIME_TAG. Even if a filename is defined for an attached file, the extension mapped by the content-type should be used in the PR_ATTACH_FILENAME and PR_ATTACH_EXTENSION properties.

The name parameter is officially "deprecated" by RFC 821. As standards evolve, Microsoft will consider specifying an alternate mapping for attached filenames.

Outbound attached messages are sent as
Content-type: message/rfc822
Messages within attached messages are encoded recursively, in their proper place. Inbound message content parts with Content-Type: multipart/digest are also mapped to embedded messages.

If uuencode with TNEF is used while encoding message content, all attachment properties and content are in the TNEF stream. The TNEF itself is a single, binary attached file named WINMAIL.DAT, encoded as described for Uuencode without TNEF.

If uuencode is used without TNEF, all attached files are treated as binary and uuencoded, following the message text. The file name is present in the uuencode header:
begin 0755 WINMAIL.DAT
... data ...
end

Attached messages are textized into the message text. The hierarchy of attached messages is always flattened; that is, messages within attached messages are pulled out to the top level.

Embedded OLE objects are discarded.

General. Attachment rendering positions are transmitted literally, using the property PR_ATTACH_RENDERING in the TNEF. If TNEF is not used, they are lost. Incoming attachments with no rendering position (including when there is no TNEF) have their rendering position set to 0xFFFFFFFF, i.e. no position within the message text.


Suggested Configuration Parameters

The following are suggestions only, not requirements. The intent is to provide a convenient list of parameters which the implementation can choose how to support.

Whether to encode using MIME or uuencode for outbound messages: boolean.

Character set to use for outbound messages: string (copied directly to charset parameter) or enumeration (translated internally to charset string).

(possibly, if not supplied by the OS) List of mappings between file extensions and content-types.


Regular Expressions

MAPI supports a limited form of regular expression notation. Regular expression notation is a compact way of specifying a group of strings that all match some criteria. A target string is said to match the regular expression if it is a member of this group of strings. Regular expressions are character strings in which plain text indicates that that text must exist in the target string, and special characters are used to indicate what variability is allowed in the target strings. MAPI uses the rules for regular expression matching only when the relational operator being used to compare strings is RELOP_RE.

Regular expressions are constructed of one or more single character regular expressions. A single character regular expression tests one character from the target string against one or more characters specified by the single character regular expression.


Single Character Regular Expressions

Single character regular expressions match at most one character from the target string. There are several types of single character regular expressions:

  • Ordinary characters. Any character that is not used in other sorts of regular expression syntax is an ordinary character. To match the regular expression, the target string must have that same character in the same position as it occurs in the regular expression. For example, the single character regular expression "g" indicates that the target string must have a "g" in the appropriate position.
  • Escaped special characters. The characters left bracket ([), right bracket (]), backslash (\), asterisk (*), period (.), dollar sign ($), and caret (^) are special in that they are used to form other types of regular expression syntax. To construct a single character regular expression that matches any one of those characters literally, preceed the character with a backslash (\). For example, the single character regular expression "\*" matches a single asterisk in the appropriate position. Recall that these rules only apply when the comparison operator is RELOP_RE, so these characters should not be escaped in all strings.
  • A period. A period (.) forms a special single character regular expression that matches any single character except NEWLINE. This indicates that the target string can have any character except NEWLINE in the position specified by the period. For example, the strings "a", "W", and "7" all match the single character regular expression ".".
  • Sets of allowed characters. Brackets ([ and ]) enclosing a set of characters indicates that any of the enclosed characters may occur in the appropriate position in the target string. The special characters period (.), asterisk (*), left-bracket ([), and backslash (\) are treated as normal characters when enclosed in brackets. Additionally, the right-bracket (]) is treated as a normal character if it is the first character in the set. For example, the single character regular expression "[]abc]" indicates that the target string can have either a right-bracket, an "a", a "b", or a "c" in the appropriate position.
  • A dash (-) between two other characters indicates a range of characters in ASCII sequence from the first character to the second. For example, the single character regular expression "[0-9]" indicates that the target string must have a digit in the appropriate position. The dash loses this meaning if it occurs as the first character in the set.
  • A caret (^) immediately following the left-bracket ([) is used to exclude the remaining characters within brackets from matching the target string. It indicates that the target string may have any character in the appropriate position except those following the caret, and NEWLINE. For example, the single character regular expression "[^0-9]" indicates that the target string cannot have a digit in the appropriate position. The caret loses this special meaning if it is not the first character within the square brackets. In addition, the left-bracket ([) and dash (-) may be excluded from matching if they immediately follow the caret, rather than immediately following the initial left-bracket ([) as previously described. For example, the regular expression "[^[]" matches any single character except for a left bracket.


Multiple Character Regular Expressions

Single character regular expressions can be combined into more complex regular expressions that match more than one character at a time. You can also apply modifiers to single character regular expressions to make them match more than one instance of the character or characters specified by the single character regular expression.

Use the following rules to construct regular expressions from single character regular expressions:

  • A single character regular expression followed by an asterisk (*) is a regular expression that matches zero or more consecutive occurrences of the single character regular expression; always as many as possible. For example, "f*" matches zero or more consecutive "f" characters.
  • A single character regular expression followed by \{m\}, \{m,\}, or \{m,n\} is a regular expression that matches a specified number of occurrences of the single character regular expression. The values of m and n must be nonnegative integers less than 255; \{m\} matches exactly m occurrences of the single character regular expression; \{m,\} matches at least m occurrences; \{m,n\} matches any number of occurrences between m and n, inclusive. Whenever a choice exists, the regular expression matches as many occurrences as possible. For example, the regular expression "[0-9]\{1,4\}" matches any sequence of 1 to 4 digits.
  • A concatenation of regular expressions is a regular expression that matches the concatenation of the strings matched by each component of the regular expression. For example, the regular expression "[0-9][a-z]" matches any string of two characters that starts with a digit and ends with a lowercase letter.
  • A regular expression enclosed between the character sequences \( and \) is a sub-expression that matches whatever the original regular expression matches. The sub-expression is placed in a internal, numbered register for use later. The registers are numbered according to the pairs of \( and \) within the whole regular expression. The first pair corresponds to register 1. For example, if a string matches the regular expression "\([0-9]*\)\([a-z]*\)", register 1 will contain whatever sequence of characters matched the regular expression "[0-9]*", and register 2 will contain whatever sequence of characters matched the regular expression "[a-z]*". There may be up to 9 sub-expressions in a regular expression.
  • The expression \n, where n is a digit from 1 through 9, matches the same string of characters stored in the internal register number n; that is, the same string of characters that the sub-expression corresponding to n originally matched. Regular expressions of the form \n are meaningless unless there is a sub-expression corresponding to n. For example, the regular expression "\([0-9]\)\1\1" matches any string which consists of the same digit three times, such as "777".
  • A regular expression preceeded by a caret (^) must match at the beginning of the target string. A regular expression followed by a dollar sign ($) must match at the end of the target string. Both may be used in the same regular expression. For example, the regular expression "^[0-9]*$" only matches strings that consist entirely of digits.


Functionality Groups

This appendix provides lists of API elements grouped by functionality. It identifies and describes each group and lists the reference entries that belong in it.


Function Groups

Many of the MAPI functions, prototypes, and related macros can be classified in groups based on which ones are used in conjunction with each other. The following lists enumerate these groups and provide additional references where appropriate.


Entry Identifier Functions

The following functions manipulate entry identifiers and message identifiers:

HrComposeEID
HrComposeMsgID
HrDecomposeEID
HrDecomposeMsgID
HrEntryIDFromSz
HrSzFromEntryID
WrapStoreEntryID

Note Except for WrapStoreEntryID, these functions may not be supported in future versions of MAPI.


Form Functions

The following functions deal with form-related objects:


Idle Routine Functions

The following functions deal with idle routines for the MAPI idle engine:

ChangeIdleRoutine
DeregisterIdleRoutine
EnableIdleRoutine
FNIDLE prototype
FtgRegisterIdleRoutine
MAPIDeinitIdle
MAPIInitIdle

Note These functions and the function prototype may not be supported in future versions of MAPI.


IMessage-On-IStorage Functions

The following functions facilitate operations on a MAPI IMessage object built on top of an underlying OLE IStorage object:

CloseIMsgSession
GetAttribIMsgOnIStg
MSGCALLRELEASE prototype
OpenIMsgOnIStg
OpenIMsgSession
SetAttribIMsgOnIStg

Note CloseIMsgSession and OpenIMsgSession may not be supported in future versions of MAPI.


IStorage Functions

The following functions perform various operations on the OLE IStorage interface:

HrIStorageFromStream
MapStorageSCode
OpenStreamOnFile

Note MapStorageSCode may not be supported in future versions of MAPI.


IUnknown Functions

The following functions provide alternate access to the OLE IUnknown interface:

UlAddRef
UlRelease

Note These functions may not be supported in future versions of MAPI.


Large Integer Functions

The following functions perform operations on large integers held in FILETIME structures:

FtAddFt
FtMulDw
FtMulDwDw
FtNegFt
FtSubFt

Note These functions may not be supported in future versions of MAPI.


MAPI Initialization Functions

The following functions are used to initiatialize and shut down MAPI for a client, and to initiate a session with MAPI:


Memory Management Functions

The following functions are used to allocate and deallocate memory:

FreePadrlist
MAPIAllocateBuffer
MAPIAllocateMore
MAPIFreeBuffer
MAPIGetDefaultMalloc

MAPIAllocateBuffer, MAPIAllocateMore, and MAPIFreeBuffer enable client applications and service providers to exchange blocks of memory. MAPIAllocateBuffer is called to initially allocate memory for a buffer; MAPIAllocateMore can be used at a later time to allocate a subsequent block of memory that is linked to the initial block. Assume when calling these allocators that the returned buffer is appropriately aligned for the CPU architecture.

The chaining of allocations supported by MAPIAllocateMore simplifies the handling of complex memory objects for clients. An array of property values, for example, can consist of numerous blocks of memory linked together by pointers that can be released with a single call to the third function, MAPIFreeBuffer. Whenever a block of memory is returned from any MAPI method, such as IMAPIProp::GetProps, MAPIFreeBuffer must be used to release it. MAPIFreeBuffer releases the initial block and any subsequent blocks.

Whenever possible, allocate all of the necessary memory with a single call to MAPIAllocateBuffer. MAPIAllocateMore exists merely as a convenience. However, if MAPIAllocateMore is used to allocate additional memory for a buffer, this memory should always be freed along with the initial buffer. Ignore any errors returned from MAPIFreeBuffer. The function almost always succeeds, and in the rare case that an error is returned, there is little that the caller can do about it.

Note Clients call the MAPIAllocateBuffer and MAPIAllocateMore functions directly, while service providers must make an indirect call, retrieving the function pointers through a call to IMAPISupport::GetMemAllocRoutines.


Notification Functions

The following functions deal with event notification:

HrAllocAdviseSink
HrDispatchNotifications
HrThisThreadAdviseSink
NOTIFCALLBACK prototype
ScCopyNotifications
ScCountNotifications
ScRelocNotifications

Note Except for HrDispatchNotifications and HrThisThreadAdviseSink, these functions may not be supported in future versions of MAPI.


Parameter Validation Macros

The following macros validate parameters in a function call:


Path Name Functions

The following functions convert path names between universal naming convention (UNC) and local drive format:

ScLocalPathFromUNC
ScUNCFromLocalPath

Note These functions may not be supported in future versions of MAPI.


Preprocessor Functions

Functions based on the following prototypes are used for message preprocessing:

PreprocessMessage prototype
RemovePreprocessInfo prototype


Profile Wizard Functions

Functions based on the following prototypes interact with the Profile Wizard:

LAUNCHWIZARDENTRY prototype
SERVICEWIZARDDLGPROC prototype
WIZARDENTRY prototype


Properties Functions

The following functions perform various operations on MAPI properties:

CreateIProp
FEqualNames
FPropCompareProp
FPropContainsProp
FPropExists
GetInstance
HrGetOneProp
HrSetOneProp
LPropCompareProp
PpropFindProp
PropCopyMore
ScCopyProps
ScCountProps
ScDupPropset
ScRelocProps
UlPropSize

Note Except for CreateIProp and ScDupPropset, these functions may not be supported in future versions of MAPI.


Provider Initialization Functions

The following entry point functions initialize service providers:


RTF Synchronization Functions

The following functions are used for Rich Text Format (RTF) operations:


String Operation Functions

The following functions perform conversions and searches on null-terminated ASCII strings:

FBinFromHex
HexFromBin
ScBinFromHexBounded
SzFindCh
SzFindLastCh
SzFindSz
UFromSz
UlFromSzHex

Note These functions may not be supported in future versions of MAPI.


Structure Validation Functions

The following functions test the validity of various structures and table elements:

FBadColumnSet
FBadEntryList
FBadProp
FBadPropTag
FBadRestriction
FBadRglpNameID
FBadRglpszW
FBadRow
FBadRowSet
FBadSortOrderSet

Note These functions may not be supported in future versions of MAPI.


Table Functions

The following functions perform various operations on MAPI tables:


Tnef Functions

The following functions are used for the MAPI Transport-Neutral Encapsulation Format (TNEF):


Property Groups

Many of the MAPI properties can be classified in groups based on which ones are used in conjunction with each other. The following lists enumerate these groups and provide additional references where appropriate.


Actual Recipient Properties

The following are the address properties for the messaging user that actually receives the message:

PR_RECEIVED_BY_ADDRTYPE
PR_RECEIVED_BY_EMAIL_ADDRESS
PR_RECEIVED_BY_ENTRYID
PR_RECEIVED_BY_NAME
PR_RECEIVED_BY_SEARCH_KEY

For more information on the address properties, see Base Address Properties.


Alternate Recipient Properties

The following are the alternate autoforwarding recipient properties:

PR_ALTERNATE_RECIPIENT
PR_ALTERNATE_RECIPIENT_ALLOWED
PR_ORIGINATOR_REQUESTED_ALTERNATE_RECIPIENT

For more properties related to autoforwarding, see Autoforwarding Properties and Originally Intended Recipient Properties.


Attachment Properties

The following are the attachment properties for a message:

PR_ATTACH_ADDITIONAL_INFO
PR_ATTACH_CONTENT_BASE
PR_ATTACH_CONTENT_ID
PR_ATTACH_CONTENT_LOCATION
PR_ATTACH_DATA_BIN
PR_ATTACH_DATA_OBJ
PR_ATTACH_ENCODING
PR_ATTACH_EXTENSION
PR_ATTACH_FILENAME
PR_ATTACH_FLAGS
PR_ATTACH_LONG_FILENAME
PR_ATTACH_LONG_PATHNAME
PR_ATTACH_METHOD
PR_ATTACH_MIME_SEQUENCE
PR_ATTACH_MIME_TAG
PR_ATTACH_NUM
PR_ATTACH_PATHNAME
PR_ATTACH_RENDERING
PR_ATTACH_SIZE
PR_ATTACH_TAG
PR_ATTACH_TRANSPORT_NAME
PR_HASATTACH
PR_PHYSICAL_RENDITION_ATTRIBUTES
PR_RENDERING_POSITION
PR_TNEF_CORRELATION_KEY

For more information on attachments, see Attachments.


Autoforwarding Properties

The following are the autoforwarding properties for a message:

PR_AUTO_FORWARD_COMMENT
PR_AUTO_FORWARDED
PR_REDIRECTION_HISTORY

For more properties related to autoforwarding, see Alternate Recipient Properties and Originally Intended Recipient Properties.


Base Address Properties

MAPI defines several groups of properties that describe a messaging user or distribution list. Each group is built around five properties known as the base address properties. When a messaging user or distribution list is included as a recipient in a message, these properties are copied to the message. The base address properties are:

PR_ADDRTYPE
PR_DISPLAY_NAME
PR_EMAIL_ADDRESS
PR_ENTRYID
PR_SEARCH_KEY

Base address properties are maintained for every address book entry and for many message recipients. Not all of the address property groups contain all five properties. Particular properties may not be defined for these groups because the likelihood of their being needed or used is not great. However, if a client or provider discovers a need for them, or for any other property undefined by MAPI, they can create their own user-defined properties. For more information about creating custom properties, see Defining New Properties.

MAPI provides these groups of address properties to save clients and service providers time and work. Included in these groups are properties that are frequently accessed. Having them within a message saves clients and service providers from having to call OpenEntry to open the address book object and either GetProps or OpenProperty to access the properties. These address book calls are expensive in code size and execution time.

The property tags for the other groups of address properties use PR_ as the standard prefix and the rest of the base property tag as a suffix, inserting a character string in the middle to further describe the recipient and the context in which the property is being used. For example, PR_SENDER_ENTRYID is the property tag for the entry identifier of the sender of a message and PR_SENT_REPRESENTING_ENTRYID is the property tag for the entry identifier of a delegate sender.

The following table lists the different groups of address properties built on the base address properties that exist in MAPI.

Address property group | Description
Base address properties | Describe a messaging user or distribution list.
PR_SENT_REPRESENTING_ properties | Describe the delegate sender of a message.
PR_RECEIVED_BY_ properties | Describe the recipient of a message.
PR_SENDER_ properties | Describe the sender of a message.
PR_RCVD_REPRESENTING_ properties | Describe the delegate recipient of a message.
PR_ORIGINAL_AUTHOR_ properties | Describe the author of the first version of a message.
PR_ORIGINAL_SENT_REPRESENTING_ properties | Describe the delegate sender of the first version of a message.
PR_ORIGINALLY_INTENDED_RECIP_ properties | Describe the recipient for whom an autoforwarded message was originally intended.
PR_ORIGINAL_SENDER_ properties | Describe the sender of the first version of a message.
PR_REPORT_ properties | Describe the recipient of a report message.


Certificate Properties

The following are the ASN.1 certificate properties:


Content Properties

The following are the content properties in the envelope of a message:

PR_CONTENT_CONFIDENTIALITY_ALGORITHM_ID
PR_CONTENT_CORRELATOR
PR_CONTENT_IDENTIFIER
PR_CONTENT_INTEGRITY_CHECK
PR_CONTENT_LENGTH
PR_CONTENT_RETURN_REQUESTED

For more information on message content and envelopes, see About Message Properties.


Conversation Properties

The following are the conversation thread properties for a message:

PR_CONVERSATION_INDEX
PR_CONVERSATION_TOPIC
PR_OBSOLETED_IPMS
PR_RELATED_IPMS

For more properties related to conversation threads, see Original Author Properties and Original Represented Sender Properties.

For more information on conversations, see Tracking Conversations.


Conversion Properties

The following are the message text conversion properties:

PR_CONVERSION_EITS
PR_CONVERSION_PROHIBITED
PR_CONVERSION_WITH_LOSS_PROHIBITED
PR_CONVERTED_EITS
PR_EXPLICIT_CONVERSION
PR_IMPLICIT_CONVERSION_PROHIBITED
PR_ORIGINAL_EITS


Criticality Properties

The following are the criticality properties for a message:

PR_IMPORTANCE
PR_ORIGINAL_SENSITIVITY
PR_PRIORITY
PR_SECURITY
PR_SENSITIVITY

For more information on criticality properties, see Message and Recipient Options.


Dialog Box Control Properties

The following are the properties for a dialog box control element:

PR_CONTROL_FLAGS
PR_CONTROL_ID
PR_CONTROL_STRUCTURE
PR_CONTROL_TYPE
PR_DELTAX
PR_DELTAY
PR_XPOS
PR_YPOS

For more information on dialog boxes, see Display Tables.


Folder Properties

The following are the properties relating to folders:

PR_ASSOC_CONTENT_COUNT
PR_COMMON_VIEWS_ENTRYID
PR_CONTENT_COUNT
PR_CONTENT_UNREAD
PR_DEFAULT_VIEW_ENTRYID
PR_FINDER_ENTRYID
PR_FOLDER_TYPE
PR_PARENT_ENTRYID
PR_STATUS
PR_SUBFOLDERS
PR_VALID_FOLDER_MASK
PR_VIEWS_ENTRYID

For more information on folders, see Folders.


Form Properties

The following are the properties for a form:

PR_FORM_CATEGORY
PR_FORM_CATEGORY_SUB
PR_FORM_CLSID
PR_FORM_CONTACT_NAME
PR_FORM_DESIGNER_GUID
PR_FORM_DESIGNER_NAME
PR_FORM_HIDDEN
PR_FORM_HOST_MAP
PR_FORM_MESSAGE_BEHAVIOR
PR_FORM_VERSION
PR_ICON
PR_MINI_ICON

For more information, see Forms.


General Object Properties

The following are the properties for any general object:


Identity Properties

The following are the address properties constituting a service provider's identity as defined within a messaging system:

PR_IDENTITY_DISPLAY
PR_IDENTITY_ENTRYID
PR_IDENTITY_SEARCH_KEY

For more information on the address properties, see Base Address Properties.

For more information on identity, see Primary Identity.


IPM Properties

The following are the interpersonal message (IPM) properties:

PR_IPM_OUTBOX_ENTRYID
PR_IPM_SENTMAIL_ENTRYID
PR_IPM_SUBTREE_ENTRYID
PR_IPM_WASTEBASKET_ENTRYID
PR_SENTMAIL_ENTRYID

For more information on interpersonal message properties, see IPM Subtree.


Message Properties

The following are the general properties for a message:

PR_ACKNOWLEDGEMENT_MODE
PR_AUTHORIZING_USERS
PR_CORRELATE
PR_CORRELATE_MTSID
PR_DELETE_AFTER_SUBMIT
PR_DISCLOSURE_OF_RECIPIENTS
PR_DL_EXPANSION_HISTORY
PR_DL_EXPANSION_PROHIBITED
PR_INCOMPLETE_COPY
PR_LANGUAGES
PR_MESSAGE_CLASS
PR_MESSAGE_DELIVERY_ID
PR_MESSAGE_FLAGS
PR_MESSAGE_SECURITY_LABEL
PR_MESSAGE_SIZE
PR_MESSAGE_SUBMISSION_ID
PR_MESSAGE_TOKEN
PR_MSG_STATUS
PR_ORIG_MESSAGE_CLASS
PR_RECIPIENT_REASSIGNMENT_PROHIBITED
PR_REPLY_RECIPIENT_ENTRIES
PR_REPLY_RECIPIENT_NAMES
PR_REPLY_REQUESTED
PR_REQUESTED_DELIVERY_METHOD
PR_TRANSPORT_MESSAGE_HEADERS
PR_X400_CONTENT_TYPE

For more information on message properties, see About Message Properties.


Message Service Properties

The following are the properties for a message service:

PR_SERVICE_DELETE_FILES
PR_SERVICE_DLL_NAME
PR_SERVICE_ENTRY_NAME
PR_SERVICE_EXTRA_UIDS
PR_SERVICE_NAME
PR_SERVICE_SUPPORT_FILES
PR_SERVICE_UID

For more information on message services, see About Message Services.


Message Text Properties

The following are the message text conversion properties:

PR_BODY
PR_BODY_CRC
PR_BODY_HTML

For more properties related to message text, see Rich Text Properties.


Original Author Properties

The following are the address properties for the original author of a message:

PR_ORIGINAL_AUTHOR_ADDRTYPE
PR_ORIGINAL_AUTHOR_EMAIL_ADDRESS
PR_ORIGINAL_AUTHOR_ENTRYID
PR_ORIGINAL_AUTHOR_NAME
PR_ORIGINAL_AUTHOR_SEARCH_KEY

For more information on the address properties, see Base Address Properties.


Original Messaging User Properties

The following are the address properties for a messaging user or distribution list entry copied from one address book to another:

PR_ORIGINAL_DISPLAY_NAME
PR_ORIGINAL_ENTRYID
PR_ORIGINAL_SEARCH_KEY

For more information on the address properties, see Base Address Properties.


Original Represented Sender Properties

The following are the address properties for a messaging user being represented by the original sender:

PR_ORIGINAL_SENT_REPRESENTING_ADDRTYPE
PR_ORIGINAL_SENT_REPRESENTING_EMAIL_ADDRESS
PR_ORIGINAL_SENT_REPRESENTING_ENTRYID
PR_ORIGINAL_SENT_REPRESENTING_NAME
PR_ORIGINAL_SENT_REPRESENTING_SEARCH_KEY

For more information on the address properties, see Base Address Properties.


Original Sender Properties

The following are the address properties for the original sender of a message:

PR_ORIGINAL_SENDER_ADDRTYPE
PR_ORIGINAL_SENDER_EMAIL_ADDRESS
PR_ORIGINAL_SENDER_ENTRYID
PR_ORIGINAL_SENDER_NAME
PR_ORIGINAL_SENDER_SEARCH_KEY

For more information on the address properties, see Base Address Properties.


Originally Intended Recipient Properties

The following are the properties for the messaging user originally intended to be the recipient:

PR_ORIGINALLY_INTENDED_RECIP_ADDRTYPE
PR_ORIGINALLY_INTENDED_RECIP_EMAIL_ADDRESS
PR_ORIGINALLY_INTENDED_RECIP_ENTRYID
PR_ORIGINALLY_INTENDED_RECIPIENT_NAME

For more information on the address properties, see Base Address Properties. Note that PR_ORIGINALLY_INTENDED_RECIPIENT_NAME is not one of the address properties.

For more properties related to autoforwarding, see Alternate Recipient Properties and Autoforwarding Properties.


Origination Properties

The following are the origination properties for a message:

PR_ORIGIN_CHECK
PR_ORIGINATING_MTA_CERTIFICATE
PR_ORIGINATOR_AND_DL_EXPANSION_HISTORY
PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED
PR_ORIGINATOR_NON_DELIVERY_REPORT_REQUESTED
PR_ORIGINATOR_RETURN_ADDRESS


Personal Information Properties

The following are the personal information properties for a messaging user:

PR_ACCOUNT
PR_ASSISTANT
PR_ASSISTANT_TELEPHONE_NUMBER
PR_BUSINESS_FAX_NUMBER
PR_BUSINESS_TELEPHONE_NUMBER
PR_BUSINESS2_TELEPHONE_NUMBER
PR_CALLBACK_TELEPHONE_NUMBER
PR_CAR_TELEPHONE_NUMBER
PR_COMPANY_NAME
PR_COUNTRY
PR_DEPARTMENT_NAME
PR_GENERATION
PR_GIVEN_NAME
PR_GOVERNMENT_ID_NUMBER
PR_HOME_FAX_NUMBER
PR_HOME_TELEPHONE_NUMBER
PR_HOME2_TELEPHONE_NUMBER
PR_INITIALS
PR_ISDN_NUMBER
PR_KEYWORD
PR_LOCALITY
PR_LOCATION
PR_MANAGER_NAME
PR_MOBILE_TELEPHONE_NUMBER
PR_OFFICE_LOCATION
PR_ORGANIZATIONAL_ID_NUMBER
PR_OTHER_TELEPHONE_NUMBER
PR_PAGER_TELEPHONE_NUMBER
PR_POST_OFFICE_BOX
PR_POSTAL_ADDRESS
PR_POSTAL_CODE
PR_PRIMARY_FAX_NUMBER
PR_PRIMARY_TELEPHONE_NUMBER
PR_RADIO_TELEPHONE_NUMBER
PR_STATE_OR_PROVINCE
PR_STREET_ADDRESS
PR_SURNAME
PR_TELEX_NUMBER
PR_TITLE

The personal information properties are used to provide supplementary identification and access information for a messaging user. They are all of property type PT_TSTRING and are all optionally exposed by messaging user objects. Their content is defined by the messaging user and the user's organization. For more information on the personal information properties, see IMailUser::IMAPIProp.


Physical Delivery Properties

The following are the physical delivery properties for a message:

PR_PHYSICAL_DELIVERY_BUREAU_FAX_DELIVERY
PR_PHYSICAL_DELIVERY_MODE
PR_PHYSICAL_DELIVERY_REPORT_REQUEST
PR_PHYSICAL_FORWARDING_ADDRESS
PR_PHYSICAL_FORWARDING_ADDRESS_REQUESTED
PR_PHYSICAL_FORWARDING_PROHIBITED
PR_REGISTERED_MAIL_TYPE


Proof of Progress Properties

The following are the properties for proof of message progress:


Provider Properties

The following are the properties for service providers:

PR_AB_PROVIDER_ID
PR_MDB_PROVIDER
PR_OWN_STORE_ENTRYID
PR_PROVIDER_DISPLAY
PR_PROVIDER_DLL_NAME
PR_PROVIDER_ORDINAL
PR_PROVIDER_UID
PR_RESOURCE_FLAGS
PR_RESOURCE_PATH
PR_RESOURCE_TYPE
PR_STATUS_CODE
PR_STATUS_STRING
PR_STORE_ENTRYID
PR_STORE_RECORD_KEY
PR_STORE_STATE
PR_STORE_SUPPORT_MASK
PR_WIZARD_NO_PAB_PAGE
PR_WIZARD_NO_PST_PAGE

For more information on service providers, see Service Provider Basics.


Recipient List Properties

The following are the recipient list properties for a message:

PR_DISPLAY_BCC
PR_DISPLAY_CC
PR_DISPLAY_TO
PR_MESSAGE_CC_ME
PR_MESSAGE_RECIP_ME
PR_MESSAGE_TO_ME
PR_ORIGINAL_DISPLAY_BCC
PR_ORIGINAL_DISPLAY_CC
PR_ORIGINAL_DISPLAY_TO


Remote Transfer Properties

The following properties deal with the transfer of a message from a remote message store to a client application:

PR_MESSAGE_DOWNLOAD_TIME
PR_REMOTE_PROGRESS
PR_REMOTE_PROGRESS_TEXT
PR_REMOTE_VALIDATE_OK

For more information on remote transfers, see Remote Transport Architecture.


Report Properties

The following are the properties for a report message:

PR_DELIVERY_POINT
PR_DISCARD_REASON
PR_DISCRETE_VALUES
PR_IPM_RETURN_REQUESTED
PR_NDR_DIAG_CODE
PR_NDR_REASON_CODE
PR_NON_RECEIPT_NOTIFICATION_REQUESTED
PR_NON_RECEIPT_REASON
PR_READ_RECEIPT_REQUESTED
PR_REPORT_TAG
PR_REPORT_TEXT
PR_REPORTING_DL_NAME
PR_REPORTING_MTA_CERTIFICATE
PR_RETURNED_IPM
PR_SUBJECT_IPM
PR_SUPPLEMENTARY_INFO
PR_TYPE_OF_MTS_USER

For more information on reports, see Report Messages.

For more properties related to reports, see Report Recipient Properties.


Report Recipient Properties

The following are the address properties for the recipient of a report:

PR_READ_RECEIPT_ENTRYID
PR_READ_RECEIPT_SEARCH_KEY
PR_REPORT_ENTRYID
PR_REPORT_NAME
PR_REPORT_SEARCH_KEY

For more information on the address properties, see Base Address Properties.

For more properties related to reports, see Report Properties.


Represented Recipient Properties

The following are the address properties for a messaging user being represented by the receiving user:

PR_RCVD_REPRESENTING_ADDRTYPE
PR_RCVD_REPRESENTING_EMAIL_ADDRESS
PR_RCVD_REPRESENTING_ENTRYID
PR_RCVD_REPRESENTING_NAME
PR_RCVD_REPRESENTING_SEARCH_KEY

For more information about how these properties are used, see Delegate Access.

For more information on the address properties, see Base Address Properties.


Represented Sender Properties

The following are the address properties for a messaging user being represented by the sender:

PR_SENT_REPRESENTING_ADDRTYPE
PR_SENT_REPRESENTING_EMAIL_ADDRESS
PR_SENT_REPRESENTING_ENTRYID
PR_SENT_REPRESENTING_NAME
PR_SENT_REPRESENTING_SEARCH_KEY

For more information about how these properties are used, see Delegate Access.

For more information on the address properties, see Base Address Properties.


Reserved Properties

The following properties are reserved for use by MAPI 1.0:

PR_AB_DEFAULT_DIR
PR_AB_DEFAULT_PAB
PR_AB_PROVIDERS
PR_AB_SEARCH_PATH
PR_AB_SEARCH_PATH_UPDATE
PR_PREPROCESS
PR_RECIPIENT_STATUS
PR_RTF_SYNC_BODY_COUNT
PR_RTF_SYNC_BODY_CRC
PR_RTF_SYNC_BODY_TAG
PR_RTF_SYNC_PREFIX_COUNT
PR_RTF_SYNC_TRAILING_COUNT
PR_SERVICES
PR_STORE_PROVIDERS
PR_TRANSPORT_KEY
PR_TRANSPORT_PROVIDERS


Rich Text Properties

The following are the Rich Text Format (RTF) properties:

PR_RTF_COMPRESSED
PR_RTF_IN_SYNC
PR_SEND_RICH_INFO

For more information on formatted text, see Formatted Text in MAPI.


Schedule Properties

The following are the properties for a schedule message:


Sender Properties

The following are the address properties for the current message sender:

PR_SENDER_ADDRTYPE
PR_SENDER_EMAIL_ADDRESS
PR_SENDER_ENTRYID
PR_SENDER_NAME
PR_SENDER_SEARCH_KEY

Transport providers are required to set the PR_SENDER_ properties to supply information about a message's originator. Transport providers set these properties on outgoing messages. When a message is sent to a variety of recipients with several messaging systems, each transmitted copy will have a different sender identity.

For more information on the address properties, see Base Address Properties.


Specialized Usage Properties

The following are the properties with specialized usage:


Subject Properties

A message's subject line is divided into two parts: a prefix and the text of the main subject. New messages, or messages that are the first in a conversation, have no prefix. Replies most often use the RE: prefix while forwarded messages use FW:. Client applications can specify any prefix, however, as well as any text to include in the main subject.

MAPI defines three message envelope properties to describe a message's subject:

PR_NORMALIZED_SUBJECT
PR_SUBJECT_PREFIX
PR_SUBJECT

PR_NORMALIZED_SUBJECT is a nontransmittable property that is calculated by message store providers when a client calls SaveChanges on a message. PR_NORMALIZED_SUBJECT is read-only to clients and is based on the contents of the other two subject properties: PR_SUBJECT, which, if set, contains a message's subject line, and PR_SUBJECT_PREFIX, which, if set, contains a subject line's prefix.

Clients can, at their discretion, set PR_SUBJECT and PR_SUBJECT_PREFIX by calling IMAPIProp::SetProps; both properties are optional.

Message store providers expect prefix characters to appear at the beginning of message subject lines and to contain from one to three non-numeric, non-whitespace, and non-punctuation characters followed by a colon and a space. Clients that need to do something different with their prefixes, such as include more than three characters or avoid the colon, should always set the PR_SUBJECT_PREFIX property explicitly and always place the prefix at the start of the subject line of the message.

Report messages attempt to preserve the value of the original PR_NORMALIZED_SUBJECT property by appending their new prefix onto the original. For example, the PR_SUBJECT_PREFIX property for a nonread report on a reply might be "Not Read: RE".

Because PR_NORMALIZED_SUBJECT is not calculated until a client calls SaveChanges to save a message, message store providers cannot guarantee its correctness before that time. When PR_SUBJECT_PREFIX is calculated rather than set by clients, its correctness cannot be guaranteed either. The unpredictability of these property values should have no effect on clients that batch and save their changes. Clients that allow their users to work with open messages without making changes might be affected.

For more information on subject properties, see Creating a Message Subject.


Supplemental Name Properties

The following are the supplemental name properties for a messaging user:


Table Access Properties

The following are the table access properties:

PR_CONTAINER_CONTENTS
PR_CONTAINER_HIERARCHY
PR_FOLDER_ASSOCIATED_CONTENTS
PR_MESSAGE_ATTACHMENTS
PR_MESSAGE_RECIPIENTS
PR_RECEIVE_FOLDER_SETTINGS

For more information on table access, see Types of Tables.


Table Row Properties

The following are the properties for a row entry in a table:

PR_DEPTH
PR_DISPLAY_TYPE
PR_INSTANCE_KEY
PR_PARENT_DISPLAY
PR_ROW_TYPE
PR_ROWID

For more information on table rows, see Retrieving Data from Table Rows.


Template Properties

The following are the template dialog box properties for an address book container:

PR_CREATE_TEMPLATES
PR_DEF_CREATE_DL
PR_DEF_CREATE_MAILUSER
PR_SELECTABLE

For more information on template identifiers, see Address Book Identifiers.


Time Properties

The following are the properties for tracking the progress of a message through time:

PR_CLIENT_SUBMIT_TIME
PR_CREATION_TIME
PR_DEFERRED_DELIVERY_TIME
PR_DELIVER_TIME
PR_EXPIRY_TIME
PR_LAST_MODIFICATION_TIME
PR_LATEST_DELIVERY_TIME
PR_MESSAGE_DELIVERY_TIME
PR_ORIGINAL_DELIVERY_TIME
PR_ORIGINAL_SUBMIT_TIME
PR_PROVIDER_SUBMIT_TIME
PR_RECEIPT_TIME
PR_REPLY_TIME
PR_REPORT_TIME

For more information on time properties on messages, see Message and Recipient Options.


Unused Properties

The following properties are not used or supported in MAPI 1.0:

PR_ATTACHMENT_X400_PARAMETERS
PR_CAPABILITIES_TABLE
PR_CONTAINER_CLASS
PR_CONTAINER_MODIFY_VERSION
PR_CONTENTS_SORT_ORDER
PR_CONVERSATION_KEY
PR_CREATION_VERSION
PR_CURRENT_VERSION
PR_DISC_VAL
PR_FILTERING_HOOKS
PR_HEADER_FOLDER_ENTRYID
PR_IPM_ID
PR_IPM_OUTBOX_SEARCH_KEY
PR_IPM_SENTMAIL_SEARCH_KEY
PR_IPM_SUBTREE_SEARCH_KEY
PR_IPM_WASTEBASKET_SEARCH_KEY
PR_MODIFY_VERSION
PR_PARENT_KEY
PR_PRIMARY_CAPABILITY
PR_TRANSPORT_STATUS
PR_X400_DEFERRED_DELIVERY_CANCEL


Structure Groups

Many of the MAPI structures can be classified in groups based on which ones are used in conjunction with each other. The following lists enumerate these groups and provide additional references where appropriate.


Address Structures

The following structures are used by clients and service providers to describe recipients or the common address dialog box:


Display Table Structures

The following structures are used by clients and service providers to describe tabbed pages, list boxes or labels and a variety of dialog boxes along with controls, check boxes or buttons to be used in dialog boxes:

DTBLBUTTON
DTBLCHECKBOX
DTBLCOMBOBOX
DTBLDDLBX
DTBLEDIT
DTBLGROUPBOX
DTBLLABEL
DTBLLBX
DTBLMVDDLBOX
DTBLMVLISTBOX
DTBLPAGE
DTBLRADIOBUTTON
DTCTL
DTPAGE


Form Structures

The following structures are used by clients and service providers to create forms or are used with existing forms to describe a print setup or properties. Other structures in this group contain arrays of structures, or arrays of pointers to form objects and message class strings.


ID Structures

The following structures are used by clients and service providers and contain an entry identifier or an array of entry identifiers representing MAPI objects, properties, or service providers. Two of these structures, FLATMTSIDLIST and MTSID, contain X.400 message transport system (MTS) identifiers.


Notification Structures

The following structures are used by clients and service providers and contain information about errors, message arrivals, changes, or events:


Property Structures

The following structures are used by clients and service providers and describe MAPI properties or the related attributes, errors, property tags, or structure arrays:


Restriction Structures

The following structures are used by clients and service providers to limit, test, define, match, filter or sort information:

SAndRestriction
SBitMaskRestriction
SCommentRestriction
SComparePropsRestriction
SContentRestriction
SExistRestriction
SNotRestriction
SOrRestriction
SPropertyRestriction
SRestriction
SSizeRestriction
SSubRestriction


Simple MAPI Structures

The following structures are used in Simple MAPI and contain information about messages, the sender or recipient, or about attachments to a message:


Table Structures

The following structures are used by clients and service providers and describe rows, or arrays of rows, and how to use them to sort information:


TNEF Structures

The following structures contain information about property or attribute processing problems related to encoding or decoding a TNEF stream:


A

Active Messaging collection
An object that contains zero or more Active Messaging objects of the same type. The Active Messaging Library supports two types of collections: large collections and small collections. With large collections, you can use the object's methods to get the first, next, last, and previous items within the collection. With small collections, you can access all items in the collection using an implied index.
Active Messaging Library
An OLE Automation programming interface that is a component of the MAPI client interface and is used primarily by Visual Basic and Visual C and C++ client application developers. The Active Messaging Library furnishes programmable objects, like Microsoft Excel objects and Microsoft Access objects, that make available properties and methods that can then be managed by Visual Basic (VB) and Visual Basic for Applications (VBA) programs. It provides a layer between the client application and the MAPI client interface component. See also Simple MAPI, Common Messaging Calls.
Active Messaging object
An object contained in the Active Messaging Library, such as a session object, folder object, or message object, that exposes properties and methods. See the Active Messaging Library documentation in the MAPI SDK.
address book
A MAPI object that manages a collection of one or more types of recipient available to a client application. A recipient can be a messaging user or a distribution list. The recipients are stored in address book containers that are organized hierarchically. At a given workstation an address book includes recipients from every address book container furnished by every address book provider in the current profile. Address books implement the IAddrBook : IMAPIProp interface.
address book container
A MAPI object that contains recipient information furnished by an address book provider. Address book containers implement the IABContainer : IMAPIContainer interface.
address book provider
A MAPI service provider object that manages zero or more address book containers, enabling users to address messages and create recipients. An address book provider can furnish containers or templates or both. A fax address book provider, for example, typically furnishes messaging user and distribution list templates but no containers. Address book providers implement the IABContainer : IMAPIContainer, IABLogon : IUnknown, IABProvider : IUnknown, IDistList : IMAPIContainer, and IMailUser : IMAPIProp interfaces. See also address book container, container, message, template. For more information, see Developing an Address Book Provider.
address properties
A fundamental set of five properties for every recipient that describes the recipient's e-mail address and address type, display name, entry identifier, and search key. For more information, see Base Address Properties.
advise sink
A MAPI object that registers for and receives notifications of specific events in other objects. The notification of an event is asynchronous to the event itself, that is, it is communicated at an indeterminate time following the event, and the object generating the event does not wait for any response to the notification. An advise sink provides a callback function for events that occur in a message store, address book, or session. Advise sinks implement the IMAPIAdviseSink : IUnknown interface.
ambiguous name resolution
(ANR) See name resolution.
application form library
A form library that supplies forms to a particular workstation. Forms installed in an application form library are available to every MAPI client application on that workstation, regardless of what message store or profile is currently active. See also folder form library, personal form library.
ASN
(Abstract Syntax Notation) An ISO standard for encoding of human-readable symbols, such as header tags, into condensed binary form. ASN.1 corresponds to CCITT standards X.208 (for the notation) and X.209 (for the encoding rules). In turn it forms part of the specifications for the X.400 and X.500 series of standards, as well as for various other specifications.
associated contents table
A table of information associated with a folder and normally stored in the "hidden" or associated part of that folder. It typically contains forms that are installed into the folder and view descriptors that are associated with the folder. See also associated information, contents table, form, standard contents table, view descriptor.
associated information
Additional information kept in a folder with a specific purpose for a client application, such as a view or a form definition. Associated information is typically not visible to the user. See also associated contents table.
attachment
A MAPI object that contains additional data, such as a file or OLE object, associated with a message. Attachments implement the IAttach : IMAPIProp interface.
attachment table
A MAPI table object that provides access to information about a message's attachments. Each row represents a message attachment.


B

bookmark
A marker that identifies a position within a table.


C

canonical form
A conventional and normalized form of any entity, such as an address, phone number, or identifier, that could exist or be presented in several different forms. An entity's canonical form is regarded as the most straightforward of its possible forms and the one that best facilitates interactions with other entities of the same type, particularly comparisons. In MAPI, canonical form is most often applied to e-mail addresses.
CCITT
The International Telegraph and Telephone Consultative Committee, an international standards committee and division of the United Nations that defines standards, such as the Electronic Data Interchange (EDI) data standard. Now called the International Telecommunications Union (ITU). CCITT stands for Comite Consultatif International Telegraphique et Telephonique, the committee's original French name. See also X.400, X.435, X.500.
client
See client application.
client application
A program that enables its user to interact with an underlying messaging system by calling functions or interface methods implemented by the MAPI subsystem or a service provider. These functions and methods are known collectively as the client interface. See also messaging application, service provider interface.
client extension
A program component that adds to the feature set of a client application, for example a handler for custom commands. Client extensions implement the IExchExt : IUnknown interface or one of its sibling interfaces. For more information, see Interfaces for Extending the Microsoft Exchange Client.
client interface
The set of interfaces and functions used by a client application. The client interface has four components: MAPI, Simple MAPI, Common Messaging Calls (CMC), and the Active Messaging Library. The last three components are layers between the client application and the MAPI component, and they make calls to MAPI. The client interface can use one or more of these four components in any combination. For more information, see Selecting a Client Interface.
CMC
See Common Messaging Calls.
common dialog box
A Microsoft Windows dialog box that is provided with the MAPI SDK. A client application uses common dialog boxes to promote an appearance both consistent within the application and consistent with other Windows-based applications. See also dialog box.
common extension set
A predefined set of Common Messaging Calls data extensions. The common extension set includes the extensions most frequently used in messaging systems and in CMC implementations, but which are not in the CMC base specification itself.
Common Messaging Calls
(CMC) A set of functions that is based upon the standard developed by the X.400 Application Programming Interface Association (XAPIA) and that is a component of the MAPI client interface. CMC is a cross-platform function set that enables a client application to be independent of the actual messaging system, operating system, and hardware used. It provides a layer between the client application and the MAPI client interface component. See also Simple MAPI, Active Messaging Library.
Common Messaging Calls data extension
A data structure that is used to add features to Common Messaging Calls (CMC) functions and structures. Data extensions can add members to existing data structures or parameters to existing CMC functions.
compound entry identifier
An entry identifier that is created by combining the entry identifier of a message store and the entry identifier of a message within the store. Compound entry identifiers are used by a client application to open messages from a nondefault message store provider. MAPI, Simple MAPI, and Common Messaging Calls applications can all use compound entry identifiers.
configuration file
A formatted file used to store a user's choices of names, features, limits, and other information that can vary among installations. See also form configuration file, MAPI configuration file.
connection number
A number that uniquely identifies an individual registration for a notification. A client application uses this number to cancel its registration.
container
A MAPI object that holds one or more other MAPI objects. Examples of containers are address book containers, distribution lists, and folders. Containers implement the IMAPIContainer : IMAPIProp interface. See also address book container, distribution list, folder, form container.
contents table
A MAPI table object that provides access to a summary view of entries in a folder or in an address book container. Each row represents a folder, a message, or a recipient, depending on which provider is implementing the table. See also associated contents table, standard contents table.
control
A MAPI object acting as a user interface (UI) for a property. A control appears as an element in a dialog box, where its value can be inspected and possibly changed by the user. For more information, see Display Table Controls.
conversation thread
A series of messages that pertain to the same topic. The topic is held in the PR_CONVERSATION_TOPIC property of each message in the thread. This property and the PR_CONVERSATION_INDEX property facilitate sorting of messages by threads.
custom message
A message with a message class other than those defined by MAPI. A custom message is created and displayed with a special purpose form server rather than with the standard send note or read note form. For more information on message class values, see PR_MESSAGE_CLASS. For more information on custom messages and form servers, see Choosing a Message Class.
custom recipient
See one-off address.
custom recipient entry identifier
See one-off entry identifier.
custom recipient table
See one-off table.
custom recipient template entry identifier
See one-off template entry identifier.


D

data extension
See Common Messaging Calls data extension.
DBCS
(Double-Byte Character Set) A mapping of a collection of characters to a set of values each of which can be either one or two bytes. Commonly used for encoding languages requiring more than 256 characters, such as Japanese Kanji. See also Unicode.
default profile
Configuration information about a session's set of message services, with which a client application logs on if no other such configuration information is specified. See also message service, profile, session.
delegate access
The ability of one messaging user to send or receive messages on behalf of another user and to access that other user's message store. The messaging users in a delegation are commonly human users, but either the delegator or the delegate could be a software application.
Deleted Items folder
A folder within the interpersonal message (IPM) subtree that is designated to hold messages marked for deletion. Also referred to as the wastebasket. See also IPM subtree.
delivery report
(DR) A report message sent to a message sender that indicates the message has been delivered to a particular recipient. A delivery report can be generated by the MAPI spooler, a message transfer agent, or a transport provider. The recipient may or may not have read the message.
dialog box
A window displayed in the user interface (UI) to solicit input from the user. It contains one or more controls. A dialog box and its controls are governed by a display table.
disk instance
A temporary file that contains executable files for a form if those executable files are not yet resident on the user's local disk. A disk instance is created any time a form is loaded from a form library.
display name
A character string that represents a MAPI object in the user interface (UI). Service providers assign display names to their objects by setting each object's PR_DISPLAY_NAME property.
display table
A MAPI table object that describes the layout of a dialog box. Each row in the table represents a control in the dialog box. Each column in the table holds data about one property of the control, such as its location, size, or type. A display table is used to display details of a messaging user, a distribution list, or a container. It can also be used to display and edit configuration parameters for a service provider.
distribution list
A MAPI object that identifies a grouping of message recipients. A distribution list can contain individual messaging users and other distribution lists. Distribution lists implement the IDistList : IMAPIContainer interface. See also messaging user, recipient.
domain
See messaging domain.
dynamic table
A table that changes as the underlying data changes. Attachment tables and message store tables are examples of dynamic tables. See also static table.


E

Electronic Data Interchange
(EDI) A standard for integrating data with various native formats into a message, which has been defined by the International Telegraph and Telephone Consultative Committee (CCITT) standards body, now called the International Telecommunications Union (ITU), and is implemented in the X.435 message-handling standard.
entry identifier
A binary value that distinguishes a MAPI object from other objects of the same type and permits clients and providers to open and access the object. Part of the entry identifier represents the service provider that defines the object, and part represents the individual object. Entry identifiers allow the MAPI subsystem to determine which service provider should handle a particular object. An object's entry identifier is stored in its PR_ENTRYID property. See also compound entry identifier, one-off entry identifier, one-off template entry identifier, long-term entry identifier, short-term entry identifier, record key, search key.
entry point function
A function in a message service dynamic-link library (DLL) called by MAPI at logon time for configuration purposes. For more information, see Implementing a Service Provider Entry Point Function.
event
A change in an object's state that can generate a notification, such as a critical error occurring or the object being modified.
event mask
A bitmask that is used to indicate one or more types of event notifications. Advise sink objects register for specific notifications using the event mask. See also advise sink, notification.
extension
See client extension, Common Messaging Calls data extension.


F

folder
A message store container object that holds messages and other folders. MAPI folders implement the IMAPIFolder : IMAPIContainer interface. See also header folder, IPM subtree, receive folder, root folder, search-results folder.
folder form library
A form library that supplies forms to a particular folder. Forms installed in a folder form library are available to every user of that folder. See also application form library, personal form library.
foreign system
An X.400 messaging term indicating a messaging system outside the messaging domain of the local X.400 network.
form
A MAPI object that enables a user of a client application to interact with a message of a particular message class. User interaction is controlled by a form server application and is based on MAPI properties corresponding to controls on the form. Form objects implement the IMAPIForm : IUnknown and IMAPIFormInfo : IMAPIProp interfaces.
form activation
The process of starting a form server to enable a user to work with a particular form within a client application.
form configuration file
A configuration file that defines a form and provides information for installing it into a form library using the IMAPIFormContainer::InstallForm method. Form configuration files must have the .CFG filename extension. See also File Format of Form Configuration Files.
form container
A MAPI object that stores form definitions. A form container can be used to locate a form definition and to activate the appropriate form server. Form containers implement the IMAPIFormContainer : IUnknown interface. See also form resolution.
form library
A form container as seen through the user interface (UI). MAPI distinguishes several types of form library, including the application form library, folder form library, and personal form library.
form library provider
A MAPI service provider object that manages one or more form libraries. Like most service providers it is a dynamic-link library (DLL). Form library providers implement the IMAPIFormContainer : IUnknown, IMAPIFormInfo : IMAPIProp, and IMAPIFormMgr : IUnknown interfaces. See also form.
form resolution
The process of mapping the message class of a particular message to the class identifier of the form server for that message, and of locating the form for that message in the appropriate form container. Form resolution determines which piece of code should be activated to manage interaction with a particular message.
form server
An application that manages a user's interaction with a form, for example responding to menu commands. Form servers implement the IMAPIForm : IUnknown, IMAPIFormAdviseSink : IUnknown, IMAPIFormFactory : IUnknown, and IPersistMessage : IUnknown interfaces, and can optionally implement the IMAPIViewAdviseSink : IUnknown interface. See also form viewer. For more information, see Developing MAPI Form Servers.
form viewer
A client application that is capable of launching a form. Form viewers implement the IMAPIMessageSite : IUnknown, IMAPIViewAdviseSink : IUnknown, and IMAPIViewContext : IUnknown interfaces. See also form server.
fuzzy level
A value that describes the degree of exactness or looseness desired when searching through a container for a target string. Lower levels of fuzziness indicate more exact matching. Higher levels return matches for more varied forms of the target string and usually require more execution time.


G

GAL
See global address list.
gateway
Software that links two or more dissimilar messaging systems, that is, systems that use different transport protocols. A gateway provides address translation and protocol and storage conversion. See also messaging system, messaging domain.
global address list
(GAL) A MAPI address book container that holds recipient entries for an entire organization and is available to all e-mail users in that organization.


H

hands-off state
A condition in which a form's storage object is unavailable for either read or write access. A form is placed in the hands-off state during a save operation to permanent storage. See also uninitialized state, normal state, no-scribble state. For more information, see Form States.
header folder
A special folder exposed by a remote transport provider. A client application can open the header folder to view only the message headers at the remote message store and decide for each message whether it is worth downloading for reading or can simply be deleted at the remote site.
hierarchy table
A MAPI table object that provides access to the tree organization of a MAPI container. Each row represents the hierarchical position of a container held within the parent container. For example, a hierarchy table is used by message store providers to display the folder hierarchy.
hook
See messaging hook provider.
hook provider
See messaging hook provider.


I

identity
A unique representation by which a service provider and its associated message service are known to a messaging system for a given session. Typically but not necessarily, the identity is supplied by an address book provider and derived from properties that identify the messaging user that initiated the session. The identity is exposed in the identity properties PR_IDENTITY_DISPLAY, PR_IDENTITY_ENTRYID, and PR_IDENTITY_SEARCH_KEY. For more information, see Primary Identity.
IID
See interface identifier.
Inbox
A folder within the interpersonal message (IPM) subtree that is designated as the default destination for incoming messages. See also IPM subtree, receive folder.
information service
See message service.
interface
A collection of related methods exposed by a given class of objects. There is normally a one-to-one correspondence between an object class and an interface, for example address book objects and the IAddrBook interface. All interfaces inherit either directly or indirectly from IUnknown. See also MAPI interface.
interface identifier
(IID) A constant that represents a particular interface and is used to request a pointer to the interface in order to call its methods. For example, the IID for the IAddrBook interface is IID_IAddrBook. Interface identifiers are defined using the IID structure, which is a specialized GUID structure.
International Telecommunications Union
(ITU) See CCITT.
interpersonal message
(IPM) A message that is sent or received by a human user rather than an application or process. Interpersonal messages have message class IPM.Note. See also IPC message, non-IPM message.
interprocess communication
(IPC) The exchange of data between two or more processes or applications. This exchange takes place solely through software, without any human intervention.
IPC message
A message that is sent and received by interprocess communication rather than by human users. See also interpersonal message, non-IPM message.
IPM
See interpersonal message.
IPM subtree
(interpersonal message subtree) An area of a folder hierarchy reserved by MAPI for interpersonal message (IPM) applications. Only information stored within the IPM subtree is visible to IPM users. Folders are commonly created to handle incoming, outgoing, sent, and deleted interpersonal messages. These, together with any other folders created for IPM usage, constitute a subtree of the message store which can be accessed through the message store's PR_IPM_SUBTREE_ENTRYID property. The default names for the common folders are the Inbox, Outbox, Sent Items folder, and Deleted Items folder.


K

key
A binary value associated with a MAPI object that can be compared with another binary value for the purpose of determining the relationship between the objects. Commonly used keys include the record key and the search key.


L

local message store
A message store provider that keeps its data on the user's local disk.
logon
The process by which a messaging user establishes a session with a messaging system through the MAPI subsystem. Logon typically involves the verification of the user's name and password and the user's selection of a valid profile. A user can log on to more than one messaging system at the same time.
logoff
The process by which a messaging user ends a session with the MAPI subsystem and the messaging system or systems it was logged on to.
long-term entry identifier
An entry identifier associated permanently with a MAPI object and unique in a global scope. It is stored with the object and in other appropriate places so that it can be used for multiple operations. See also short-term entry identifier.


M

mail user
See messaging user.
MAPI
(Messaging Application Programming Interface) A messaging architecture and a client interface component.

As a messaging architecture, MAPI enables multiple applications to interact with multiple messaging systems across a variety of hardware platforms. See also MAPI subsystem, messaging system.

As a client interface component, MAPI is the complete set of functions and object-oriented interfaces that forms the foundation for the MAPI subsystem's client application and service provider interfaces. In comparison with Simple MAPI, Common Messaging Calls (CMC), and the Active Messaging Library, MAPI provides the highest performance and greatest degree of control to messaging-based applications and service providers.

MAPI configuration file
A configuration file, MAPISVC.INF, that contains information about every message service and service provider installed on a workstation. For more information, see Message Services and Profiles.
MAPI interface
A set of related methods that describe the behavior of a MAPI object. All MAPI interfaces derive from the OLE base interface, IUnknown.
MAPI object
An object that supports the OLE Component Object Model (COM), implementing one or more interfaces derived from the IUnknown interface. It is implemented or used by a MAPI compliant service provider or client application, or by MAPI itself.
MAPI spooler
A MAPI process that handles the sending and receiving of messages between client applications and most messaging systems. A tightly coupled message store and transport provider does not use the spooler. See also client application, messaging system.
MAPI subsystem
The set of dynamic-link libraries (DLLs) provided by MAPI that enable interaction between client applications and service providers. The MAPI subsystem DLLs implement the MAPI spooler, the client interface, the service provider interface, and the support object.
message
A MAPI object containing information that can be sent to one or more recipients by means of a messaging system, or posted to a public folder. The principal parts of a message are the message content and the message envelope. Messages implement the IMessage : IMAPIProp interface. See also message text, post, recipient.
message body
See message text.
message class
A character string property that is assigned to every MAPI message, identifying the type of the message. The message class determines behavior such as selecting the appropriate receive folder and launching a form for the message. Message class strings are stored in the PR_MESSAGE_CLASS property.
message content
The portion of a message representing the information the sender wishes to communicate to each recipient. The message content includes the message text and any attachment objects. It excludes the message envelope. Messages of the same message class are expected to have similar content structure.
message envelope
The portion of a message used for routing and delivery to each recipient. The message envelope includes the address properties for each recipient, header information such as the sender and subject, and specifications for responding and exception handling. It excludes the message content. See also message text, message transfer envelope.
message identifier
An ASCII string used by Simple MAPI to access an incoming message. A message identifier is valid only during the session in which it is assigned a value by the MAPIFindNext function, and does not correspond to the message reference used by CMC. For more information, see Receiving a Message: Simple MAPI Sample.
message preprocessor
A dynamic-link library (DLL) that runs on a client workstation and operates on outbound messages before they are given to any transport provider. For example, a message preprocessor might make a local copy of every outgoing message. A message preprocessor can be called selectively based on each recipient's address type or entry identifier. Also referred to as a preprocessor. See also messaging hook provider. For more information, see Developing a Hook Provider or Preprocessor.
message reference
A counted string structure used by CMC to access a message within a mailbox. A message reference is valid only during the session in which it is assigned a value by the cmc_list function, and does not correspond to the message identifier used by Simple MAPI.
message service
A group of one or more related service providers installed and configured by a single body of code. For example, CompuServe might furnish an address book provider, message store provider, and transport provider all designed to interface with the CompuServe message service. For more information, see Message Services and Profiles.
message service table
A MAPI table object that provides access to information about every message service in the current profile, such as the service's name, service providers, and associated files.
message site
A MAPI object that handles the manipulation of form objects. Message site objects implement the IMAPIMessageSite : IUnknown interface.
message store
A MAPI object that contains messages and folders organized hierarchically and that implements the IMsgStore : IMAPIProp interface. See also folder, message.
message store provider
A MAPI service provider object that manages one or more message stores, handling message distribution, organization, and storage. Message store providers implement the IAttach : IMAPIProp, IMAPIFolder : IMAPIContainer, IMessage : IMAPIProp, IMsgStore : IMAPIProp, IMSLogon : IUnknown, and IMSProvider : IUnknown interfaces. For more information, see Developing a Message Store Provider.
message store table
A MAPI table object that provides access to information about every message store in the current profile.
message text
The principal content of an interpersonal message, that is, a message of message class IPM.Note. Message text can optionally be used in other message classes. It is the main portion of the message content, typically displayed to each recipient as an immediate result of opening the message. It excludes any attachment objects. Also referred to as the message body.
message transfer agent
(MTA) The X.400 term for the part of a message transfer system (MTS) that interfaces with clients of that MTS. A MAPI transport provider commonly interfaces with a message transfer agent.
message transfer envelope
(MTE) The X.400 term for the P1 or delivery envelope, which contains the information needed to deliver a message, as opposed to the information used to display it to a recipient. See also message envelope. For more information, see the PR_RECIPIENT_TYPE property.
message transfer system
(MTS) The X.400 term for a messaging system.
messaging application
A program that uses the MAPI client interface to pass messaging requests, such as requests to send and receive messages, to and from a messaging system. A messaging application is a type of client application.
messaging domain
A collection of interconnected messaging users that share a common addressing scheme and transport protocol. Communication with a messaging user in the same messaging domain does not involve reformatting or address translation. Communication with a messaging user in another messaging domain typically requires the use of a gateway. Also referred to as a domain or a site.
messaging hook provider
A MAPI service provider object that runs on the same machine as the MAPI spooler and performs special processing on inbound and outbound messages. Messaging hook providers implement the ISpoolerHook : IUnknown interface. A messaging hook provider can be called for all inbound messages, all outbound messages, or both. Also referred to as a spooler hook or a hook provider. See also message preprocessor. For more information, see Developing a Hook Provider or Preprocessor.
messaging service
See message service.
messaging system
A product that enables electronic communication over a network, such as fax, CompuServe, or the Internet. Typical clients of a messaging system include an individual computer with a modem and a local area network with a gateway.
messaging transport provider
See transport provider.
messaging user
A MAPI object that describes an individual recipient of a message. Messaging users implement the IMailUser : IMAPIProp interface. See also distribution list.
MIME
(Multipurpose Internet Mail Extensions) A set of enhancements to SMTP allowing an Internet message to include a mixture of audio, image, video, and text components, and to accommodate a variety of international character sets. MIME messages are identified by a MIME header in the top level of the SMTP header. The MIME mechanisms are specified in the RFC 1341 document.
MTA
See message transfer agent.
MTE
See message transfer envelope.
MTS
See message transfer system.
multivalued property
A property that can contain many values of the same type. Its property type has MV_FLAG set, and its property value contains multiple values of the specified property type. See also single-valued property. For more information, see About Property Types.


N

name resolution
The process of associating a string with a valid address for a particular messaging system. An unresolved name lacks an entry identifier. The names of all recipients for a message must be resolved before the message can be sent. See also recipient, resolved recipient, unresolved recipient.
name space
The set of all possible named property names within a property set. The GUID that is part of each property's name is unique to each property set and guarantees that no property names from different name spaces can be the same.
named property
A user-defined property whose principal designation is by a unique name rather than by a property identifier. Because of name-identifier mapping, a named property is valid in any messaging domain and any session. Every named property belongs to a property set, each member of which uses the same GUID for the first part of its name. For more information, see Named Properties.
name-identifier mapping
A bidirectional, persistent one-to-one mapping between the name and the property identifier of a named property. Name-identifier mapping is provided by certain implementations of the IMAPIProp::GetIDsFromNames and IMAPIProp::GetNamesFromIDs methods. For more information, see Supporting Named Properties.
NDR
See nondelivery report.
no-scribble state
A condition in which a form's storage object is available only for read access; write access is prohibited. A form is placed in the no-scribble state during a save operation to enable the operation to finish uninterrupted. See also uninitialized state, normal state, hands-off state. For more information, see Form States.
non-IPM message
(non-interpersonal message) A message that is meant to be sent or received by an application rather than by a human user, such as a notification from a workgroup scheduling application or an IPC message. See also interpersonal message.
nondelivery report
(NDR) A report message sent to a message sender that indicates the message could not be delivered to a particular recipient. A nondelivery report can be generated by the MAPI spooler, a message transfer agent, or a transport provider. Many situations can cause nondelivery reports to be generated, such as an inaccurate recipient address, unavailable transport providers, or an inoperative network.
nonread notification
(NRN) See nonread report.
nonread report
(NRN) A report message from a message store provider to a message sender that indicates the message was not read by a particular recipient, that is, the client application did not display the message contents to the recipient before the recipient deleted the message or before a specified expiration time.
nontransmittable property
A property that is not sent along with the message it is associated with. Nontransmittable properties are typically those that apply only in the sending environment, such as PR_DELETE_AFTER_SUBMIT, or only in the receiving environment, such as PR_HASATTACH. See also transmittable property.
normal state
A condition in which a form's storage object is available for both read and write access. A form is typically in the normal state unless a save or close operation is in process. See also uninitialized state, no-scribble state, hands-off state. For more information, see Form States.
notification
A communication advising a MAPI object of the occurrence of an event in another MAPI object. The notification is asynchronous to the event, that is, it is communicated at an indeterminate time following the event, and the object generating the event does not wait for any response to the notification. The object receiving the notification is referred to as the advise sink. Advise sinks register for notification of specific events in an object, such as critical errors, by calling that object's Advise method. See also registration.


O

OID
(object identifier) A value specifying the nature of an X.400 object. MAPI uses OIDs for various purposes, such as indicating the types of attached files. "Object" is a much more generalized concept in X.400 than in object-oriented programming. It can mean an algorithm, application, body part type, character set, external parameter, or message type, among other things. Also, it usually refers to a class of things, such as CRC-32, rather than one particular implementation of a 32-bit CRC (cyclic redundancy code).
one-off
British jargon for something that is used only once and not retained permanently. Also referred to as one-shot.
one-off address
A messaging address that represents a recipient that is not in the current address book. A one-off address is created by a client application or a service provider, either by presenting a complete address string for name resolution or by using a template supplied by an address book provider. An address string without an explicit address type is assumed to be an Internet address. Also referred to as a custom recipient. See also one-off template entry identifier.
one-off entry identifier
An entry identifier created from a one-off address and a display name. Also referred to as a custom recipient entry identifier. For more information, see Address Book Identifiers.
one-off table
A MAPI table object that provides access to information about supported one-off templates. Also referred to as a custom recipient table.
one-off template
A template for creating a one-off address.
one-off template entry identifier
An entry identifier held in an address book provider's one-off table and used to access a one-off template for creating a one-off address. Also referred to as a custom recipient template entry identifier. For more information, see Address Book Identifiers.
Outbox
A folder within the interpersonal message (IPM) subtree that is designated to hold outgoing messages until they are sent. See also IPM subtree.


P

PAB
See personal address book.
personal address book
(PAB) A modifiable MAPI address book container that holds recipient entries either created by the user or copied from other address book containers. Each session can optionally designate a container to act as the PAB. Personal address book objects are commonly contained in files with the .PAB filename extension.
personal folders
A personal message store as seen through the user interface (UI).
personal form library
A form library that supplies forms to a particular client application. Forms installed in a personal form library reside in a hidden folder of the default message store and are available only to the creating client application. See also application form library, folder form library.
personal message store
(PST) A MAPI message store object that is created by a user and is stored in a file with the .PST filename extension.
post
The action of storing a message in a publicly known location such as a public folder. A message is posted for the purpose of making a single copy widely available for reading by human users or processing by an application.
preprocessor
See message preprocessor.
primary identity
An object, commonly an address book entry, that represents the user of a MAPI session. The primary identity is supplied by a service provider and exposed in the properties PR_IDENTITY_ENTRYID, PR_IDENTITY_SEARCH_KEY, and PR_IDENTITY_DISPLAY.
probe
An X.400 messaging term indicating a message that has a specific message class identifier but no content. A probe is used by X.400 message senders to determine whether a message of a particular message class can be sent to a particular recipient, and if so, how.
profile
Configuration information about the set of message services for a session. Profiles are created from information stored in the MAPI configuration file, MAPISVC.INF. A profile can be modified by MAPI, a service provider, or a MAPI configuration interface. See also message service.
profile name
A text string that identifies a particular profile.
profile provider
A MAPI service provider object that manages one or more profile sections. Profile providers implement the IProfSect : IMAPIProp interface. See also profile.
profile section
A MAPI object providing access to the configuration information of a service provider or message service. A profile section can contain information provided or used by MAPI, a message service, a service provider, or a client application.
profile table
A MAPI table object that provides access to the name of every profile on a particular computer.
property
A data attribute of a MAPI object that implements the IMAPIProp : IUnknown interface. Such an object exposes its defined properties to other objects that call IMAPIProp. The same property can be defined on more than one type of MAPI object. The information that designates a MAPI property is contained in its property tag. The property's actual data contents are held in its property value. See also named property. For more information, see Properties.
property identifier
A unique 16-bit integer value that identifies a particular property. The property identifier is contained in the high-order 16 bits of the property tag. See also named property. For more information, see About Property Identifiers.
property page
One section or page of a property sheet, accessed by selecting one of the property sheet tabs.
property set
A group of named properties specified by a GUID. Each named property in the set has the GUID as part of its name, so the GUID identifies a name space. A property set can be user-defined, in which case there is no restriction on the individual property names. In a MAPI-defined name space such as PS_PUBLIC_STRINGS, names must be selected that do not conflict with existing names. For more information, see Property Names and Property Sets.
property sheet
A common dialog box that is used to display configuration information to the user and to enable the user to modify that information. A property sheet contains a collection of one or more property pages.
property tag
A 32-bit unsigned integer value that contains the unique identifier and type of a property. The high-order 16 bits contain the property identifier, and the low-order 16 bits contain the property type. See also named property, property value. For more information, see About Property Tags.
property type
A 16-bit integer value that describes the data type for a property and whether it can contain a single value or multiple values. The property type is contained in the low-order 16 bits of the property tag. For more information, see About Property Types.
property value
The current data contents of a property. A property value can consist of a single item of data or multiple items of data. See also multivalued property, single-valued property, property tag. For more information, see SPropValue.
provider
See service provider.
provider table
A MAPI table object that provides access to information about every currently loaded service provider.
proxy address
A non-native e-mail address for a recipient, that is, an address meaningful outside of the recipient's messaging domain, such as an Internet or fax address.
PST
See personal message store.
public folder
One of a set of folders made available by a message store and visible to every messaging user that logs on to that message store.


R

read flag
A flag setting, MSGFLAG_READ, that is used in the PR_MESSAGE_FLAGS property of a message to mark it as having been read. The read flag can be set in a variety of situations, including opening, printing, and copying of the message. The read flag being set does not necessarily indicate that the message has been physically read by a human user or acted upon by an application.
read notification
(RN) See read report.
read receipt
See read report.
read report
(RN) A report message from a message store provider to a message sender that indicates the read flag has been set for the message by a particular recipient. A read report can be sent in a variety of situations; its being sent does not guarantee the intended recipient has physically read the message.
receive folder
A MAPI folder object that is designated as the destination for any incoming message belonging to a particular message class. Typically, the receive folder is the Inbox in the interpersonal message (IPM) subtree. See also IPM subtree.
recipient
An address book entry and a destination for a particular message.

As an address book entry, a recipient is one of the objects held in an address book container, providing e-mail addressing information for a messaging user or a distribution list.

As a destination for a particular message, a recipient is a user or group of users designated to receive that message. It can be a messaging user, distribution list, or one-off address.

recipient list
A collection of recipients associated with a message. A recipient list can contain zero or more recipients of any type, in any combination, and in any order.
recipient table
A MAPI table object that provides access to information about the recipient list of a message. Each row in the table contains information about one recipient.
record key
A binary value that can be directly compared with other record keys to help find references to a MAPI object. An object's record key is stored in its PR_RECORD_KEY property. See also search key, entry identifier.
registration
A request on the part of a client application or MAPI to receive notifications about a specific type of event. See also notification.
registry provider
See form library provider.
report
A message sent to a recipient providing the status of a message that recipient had originated and sent. A report can be generated by a service provider, a messaging system component, or the MAPI subsystem. See also delivery report, nondelivery report, read report, nonread report.
resolution
See form resolution, name resolution.
resolved recipient
A messaging user or distribution list that has been assigned an entry identifier and an address for a particular messaging system. See also name resolution, unresolved recipient.
restriction
A set of criteria imposed against a table to filter the rows of the table, limiting a user's view of the table's data to only those rows that meet the criteria. For more information, see About Restrictions.
root folder
The MAPI folder object that appears at the top of a message store's folder hierarchy. Only one root folder can exist in a message store. Root folders are invisible to the user because of their inability to be moved, copied, renamed, or deleted. Like most folders, a root folder can contain messages and other folders. See also IPM subtree.
rule
A specification of an automated response to a particular event. Rules are commonly used to route incoming e-mail; such a rule could, for example, store an incoming message meeting certain conditions in a specified folder. A rule can be implemented by a notification callback function or a messaging hook provider. It can be applied to personal folders and to a public folder.


S

search key
A binary value that can be directly compared with other search keys to help find objects related to a MAPI object. An object's search key is stored in its PR_SEARCH_KEY property. See also record key, entry identifier.
search-results folder
A MAPI folder object that contains links to messages that match specified search criteria. A search-results folder can be saved across sessions if desired. It cannot contain other folders or messages, nor can a folder or message be created in it or moved into it.
section
A part of either a session profile or a form configuration file containing interrelated items of information. See also profile section.
secure property
A property of a profile section with a property tag in the range 0x6600 through 0x67FF. A secure property is set by a service provider, and is encrypted and invisible to a client application. To view a secure property, it is necessary to ask specifically to view it. Secure properties are typically used for credentials such as passwords.
Sent Items folder
A folder within the interpersonal message (IPM) subtree that is designated to hold copies of messages after they are sent. These copies are saved only if the message store provider supports this functionality and the user of the client application requests it. See also IPM subtree.
service provider
A MAPI component that allows a client application to use the services of a messaging system. A service provider is typically part of a message service and offers address book, form management, message store, messaging hook, profile section, or transport services. See also address book provider, form library provider, message store provider, messaging hook provider, profile provider, transport provider. For more information, see Service Provider Basics.
service provider interface
(SPI) The set of interfaces and functions that are implemented or used by service providers. The MAPISPI.H header file contains definitions of all the interface methods and functions in the service provider interface.
session
An active connection between a client application and the MAPI subsystem. As part of the logon procedure, which initiates the session, the client application selects a profile, which identifies the available messaging operations and the service providers available to handle the operations. A session implements the IMAPISession : IUnknown interface.
session handle
A handle to a session initiated by a client application using Simple MAPI or Common Messaging Calls. Session handles are returned by the MAPILogon or MAPILogonEx function at logon time.
session pointer
A pointer to a MAPI session made available to the client application that logs on to the session. A session pointer is unique to the initiating client and is not valid in any other task.
shared session
A MAPI session that can be used by multiple client applications on a given computer.
short-term entry identifier
An entry identifier of limited duration and scope. It is typically used only for a single operation and is not stored for later use. It can, however, be converted into a long-term entry identifier.
Simple Mail Transfer Protocol
(SMTP) An Internet standard for electronic mail among clients having common access to a server for message storage. The SMTP standard is specified in the RFC 821 document, and the message format is included in the RFC 822 document. For more information, see Mapping of Internet Mail Attributes to MAPI Properties.
Simple MAPI
A set of functions that is a component of the MAPI client interface and that enables basic messaging features to be added to a client application. It provides a layer between the client application and the MAPI client interface component. See also Common Messaging Calls, Active Messaging Library.
single-valued property
A property for which the data structure contains one property value of the specified property type. See also multivalued property. For more information, see About Property Types.
site
See messaging domain.
SMTP
See Simple Mail Transfer Protocol.
SPI
See service provider interface.
spooler
See MAPI spooler.
spooler hook
See messaging hook provider.
standard contents table
A table of the information in a folder that is normally visible to the user. It typically contains messages and subfolders that belong to the folder. See also associated contents table, contents table, form, message, view descriptor.
static table
A table that does not change as its underlying data changes. Provider and profile tables are examples of static tables. See also dynamic table.
status table
A MAPI table object that provides access to information about each service provider in the active profile, the MAPI spooler and MAPI subsystem, and the address book. The status table describes the state of a MAPI session.
store-and-forward messaging
A messaging model wherein messages are forwarded from a local message store to a component that saves and delivers them if possible. If delivery is not possible with the requested transport provider, this component either forwards messages to another transport provider or holds onto them until the requested transport provider is available. With MAPI, the MAPI spooler performs the store-and-forward function.
subscription
See registration.
support object
A MAPI object presented to a service provider at logon time that furnishes implementations of commonly used methods as well as certain contextual data such as the last error. For more information, see Using A Support Object.


T

table
A MAPI object that provides access to a summary view of object data in row and column format. Tables implement the IMAPITable : IUnknown interface. Each row represents an instance of an object; each column represents a property on that object. See also associated contents table, attachment table, contents table, display table, hierarchy table, message service table, message store table, one-off table, profile table, provider table, recipient table, standard contents table, status table.
Telephony Application Programming Interface
(TAPI) A set of functions that allows applications to use telephone lines for transporting data across a network without requiring information on details of how the transport process works.
template
A common dialog box that is used for creating new address book entries, such as a one-off address, of a particular type. A template can be viewed as an entire schema that specifies the properties for the dialog box and the code that relates them.
template identifier
An entry identifier for a recipient that enables its address book provider to control its behavior if it is copied into a different address book container. A template identifier can support a messaging user or a distribution list and allows the destination provider to access the original provider's implementation. The template identifier is held in the recipient's PR_TEMPLATEID property. For more information, see Address Book Identifiers.
tightly coupled
Describes a relationship between two or more providers that enables them to communicate directly with each other without using all of the interface provided by MAPI. A tightly coupled message store provider and transport provider can bypass the MAPI spooler. A tightly coupled address book provider and transport provider can pass a recipient between them using only an entry identifier and without opening a property interface.
TNEF
See Transport-Neutral Encapsulation Format.
transmittable property
A property that is sent along with the message it is associated with. Transmittable properties are those that apply in both the sending and receiving environments, such as PR_IMPORTANCE and PR_RTF_COMPRESSED. See also nontransmittable property.
Transport-Neutral Encapsulation Format
(TNEF) A MAPI-defined method of passing MAPI message properties that are not supported by a messaging system. The outbound transport provider invokes the method to bundle all the unsupported properties into a single binary stream. The transport provider may then have to encode the stream into a format its messaging system can handle. The stream accompanies the message through the transport process as an attachment, is decoded if necessary by the inbound transport provider, and is finally passed to TNEF to reconstitute the MAPI properties. See also property.
transport provider
A MAPI service provider object that is responsible for transferring messages between a message store and an underlying messaging system that delivers the messages. Transport providers implement the IXPLogon : IUnknown and IXPProvider : IUnknown interfaces. For more information, see Developing a Transport Provider.


U

UNC
(universal naming convention) A network resource name for a share point on a server, consisting of the string

\\<server name>\<share point name>

As opposed to a resolved drive letter such as S:, a UNC name is usable without alteration from any task on any computer that has access to the share point.

Unicode
A mapping of most known language characters to a set of 16-bit values. Unicode is a worldwide encoding standard and is used exclusively by Windows NT at the system level. See also DBCS.
uninitialized state
A condition in which a form's storage object is available only for write access; read access is prohibited. A form is placed in the uninitialized state from the time of its creation until it has been loaded with default or supplied data. See also normal state, no-scribble state, hands-off state. For more information, see Form States.
unresolved recipient
A messaging user or distribution list that has not been assigned an entry identifier and an address for a particular messaging system. See also name resolution, resolved recipient.


V

verb
A command appearing in the menu of a form. MAPI defines standard verbs like Compose, Send, and Close.
view
A list of parameters and operations applied to a MAPI table object, commonly the contents table of a folder. A view defines a particular way to display the data in the table, for example which columns, in which display order, and in which sort order. Some applications enable views to be saved.
view context
A MAPI object that supports commands for printing and saving a form and for navigating between forms. View contexts implement the IMAPIViewContext : IUnknown interface.
view descriptor
A message of a specific message class which appears in the associated contents table of a folder and specifies a view on that folder. A view descriptor encodes the information in the view for use by a client application.


W

wastebasket
See Deleted Items folder.
Windows Messaging System
(WMS) The MAPI subsystem that is implemented on any of the Microsoft Windows operating systems.


X

X.400
An international message-handling standard for connecting e-mail networks and for connecting users to e-mail networks. X.400 is published by the International Telegraph and Telephone Consultative Committee (CCITT) standards body, now called the International Telecommunications Union (ITU). The X.400 Application Programming Interface Association (XAPIA) defines programming interfaces to X.400. MAPI applications are fully interoperable with X.400 messaging applications.
X.435
An international message-handling standard that is published by the International Telegraph and Telephone Consultative Committee (CCITT) standards body, now called the International Telecommunications Union (ITU), and that implements the Electronic Data Interchange (EDI) standard for integrating data with various native formats into a message.
X.500
An international message-handling standard for directory services, published by the International Telegraph and Telephone Consultative Committee (CCITT) standards body, now called the Internal Telecommunications Union (ITU).
X.509
An international message-handling standard for message authentication and encryption. X.509 is published by the International Telegraph and Telephone Consultative Committee (CCITT) standards body, now called the Internal Telecommunications Union (ITU).
Xapia
The X.400 Application Programming Interface Association, the standards-setting body for programming interfaces to X.400 components. XAPIA also defines the Common Messaging Calls inteface component.


Topic Not Found

No matching topic was found. Some possible reasons and remedies are as follows:

  • The file (.chm) that contains the destination topic is not in the expected location.

Remedy: Rerun the MSDN Library Setup.

  • The file (.chm) that contains the current topic or destination topic is out-of-date and the link is no longer valid.

Remedy: Install the latest version of the MSDN Library.

  • The MSDN Library CD is not in the CD-ROM drive.

Remedy: Insert the MSDN Library CD into the CD-ROM drive.