I originally wrote this document as the first appendix of D.A.M.E . We dropped it from the final manuscript for scheduling reasons.


Additional Exchange 4.0 File Formats

Outside of the standard APIs, a Microsoft Exchange application may find it useful to duplicate certain client functions, such as creating and manipulating folder shortcuts, message links, or view descriptors.

Caveat

All of the file formats documented here apply only to the Microsoft Exchange client software in version 4.0 and related minor versions (4.1, etc.). They are not guaranteed to work on other MAPI clients, or later versions of Microsoft Exchange.

Folder Shortcuts

The Exchange Client supports a special file format through which users can create Windows Explorer-style shortcuts to folders within MAPI message stores. In Windows 95 and Windows NT 4.0, a desktop shortcut is a component object supporting IShellLink, made persistent within the filesystem as a file with the .LNK suffix through the IPersistFile or IPersistStream interfaces. The Windows Explorer shell creates shortcuts when the user drags an object onto the desktop, or else when the user drags an object into another folder with both the Control and Shift keys depressed. When the user opens the shortcut, the shell queries the shortcut object for the identity of its destination (via IShellLink::GetPath or IShellLink::GetIDList), then opens that destination object instead.

Exchange Client folder shortcuts are not component objects in the manner of shell links. They are simply binary files with the .XNK suffix, associated with the Exchange Client through entries in the system registry, into which the Exchange Client writes sufficient information to locate and display the folder again upon request. The Exchange Client creates folder shortcuts when the user invokes the File - Create Shortcut command. When the user opens a folder shortcut, the shell passes the shortcut file to the Exchange Client, which reads the necessary information from the file to create a new viewer window on that folder.

Format of the shortcut

The shortcut file consists of a block of header information, describing the window in which to display the folder, followed by a series of long-term entry identifiers, describing a series of MAPI objects to open, each against the previous object in the series. The first object in the series must be a message store, and each object thereafter a folder within that message store.

Header

The header consists of 14 32-bit DWORDs, as depicted in Table A-1.

Byte Offset Type Contents
0 DWORD Version number of folder shortcut structure. This must have the value 5.
4 DWORD Object type code, as might be returned by IMAPIProp::OpenEntry. This must have the value MAPI_FOLDER (3).
8 DWORD Must be zero (0).
12 DWORD Version number of following window definition fields. This must have the value 5.
16 DWORD Code passed to the ShowWindow API when displaying the viewer window: e.g. SW_SHOWNORMAL, SW_SHOWMINIMZED, etc.
20 DWORD Origin of left-hand border of viewer window, in screen pixels.
24 DWORD Origin of top border of viewer window, in screen pixels.
28 DWORD Width of viewer window, in screen pixels.
32 DWORD Height of viewer window, in screen pixels.
36 DWORD Offset within window of splitter bar between the folder (left-hand) and message (right-hand) panes of the viewer window.
40 DWORD Nonzero if the viewer window is displaying the folder pane.
44 DWORD Nonzero if the viewer window is displaying the toolbar.
48 DWORD Nonzero if the viewer window is displaying the status bar.
52 DWORD Byte count of remainder of file

Table A-1 Header of a folder shortcut file

Series

The remainder of the file describes each object in turn that the Exchange Client must open in order to display the sought folder. It consists of a sequence of records, each describing a MAPI object to open, and following the format given in Table A-2, concluded by a terminating sequence of two zero bytes. The final byte count field in the file header contains the sum of the sizes of these records and the size of the terminator.

Byte Offset Type Contents
0 DWORD Size of record, in bytes, including this field
4 DWORD Object type code, as might be returned by IMAPIProp::OpenEntry. This must have the value MAPI_STORE (1) for the first record, and MAPI_FOLDER (3) for each succeeding record.
8 DWORD Byte count of next field
12 n/a Data of persistent entry identifier for this object
unknown 4, 5, 6, or 7 BYTEs Pad bytes sufficient to make the size of this record a multiple of 4. Every record must have at least 4 pad bytes.

Table A-2 Record for one MAPI object in a folder shortcut file. The byte offset given is relative to the beginning of the record, not the beginning of the file.

Every folder shortcut will have at least two of these records: one for the store to open on the session, and one for a folder to open on the store. A folder shortcut may specify additional folder objects to open as well, with the Exchange Client opening each new folder entry identifier on the previous MAPI folder object in the sequence. The Exchange Client will display the final object opened.

Message Links

When attaching a message to another message under composition, a user may elect to include a link to the message instead of attaching the entire message. An icon representing the linked message then appears in the message under composition. This message link references the destination message, containing enough information to allow a recipient of the outer message to open the link and thus open the linked message.

Format of the link

To create a message link within a message, the Exchange Client creates an attachment on the outer message with PR_ATTACH_METHOD as ATTACH_OLE and PR_ATTACH_TAG as OID_OLE2_STORAGE, such that the attachment contains a structured storage instance IStorage. The Exchange Client stamps this storage (via WriteClassStg) with the class identifier {00020D09-0000-0000-C000-000000000046}, marking it as a message link, then creates a set of streams in the root storage to describe the destination message. Table A-3 summarizes these streams and their contents.

Name Contents
MailMsgAttMdb Long-term entry identifier of the MAPI message store hosting the destination message
MailMsgAttFld Long-term entry identifier of the folder containing the destination message
MailMsgAttMsg Long-term entry identifier of the destination message
MailMsgAttSubject The subject of the destination message, as used in the icon representing the link. NUL-terminated string of 8-bit characters in the code page of the link creator.
MailMsgAttIcon A metafile of the icon representing the link, as returned by GetMetaFileBitsEx.

Table A-3 Streams in the storage for a message link

View Descriptors

Chapter 8 briefly touched upon the format of view descriptors, the messages that encode the views used by the Exchange Client.

Locations of View Descriptors

All views are messages of class IPM.Microsoft.FolderDesign.NamedView in the associated contents table of some folder.

Common Views

Common views appear in the top bin of the Views - Personal Views cascade menu. They always appear, regardless of the current folder. Users cannot modify common views.

Common views are stored in the default message store, in the IPM_COMMON_VIEWS folder identified by the PR_COMMON_VIEWS_ENTRYID property on this store. (This property is valid only if the FOLDER_COMMON_VIEWS_ENTRYID flag is set in the PR_VALID_FOLDER_MASK property on the store.) The Exchange Client setup program installs common views into a message store, where they are available to all users of that store.

Personal Views

Personal views appear in the bottom bin of the View - Personal Views cascade menu. They always appear, regardless of the current folder. Users define and modify personal views.

Personal views are stored in the default message store, in the IPM_VIEWS folder specified by the PR_VIEWS_ENTRYID property on this store. (This property is valid only if the FOLDER_VIEWS_ENTRYID flag is set in the PR_VALID_FOLDER_MASK property on the store.) Only the user that created a personal view has access to it.

Folder Views

Folder views appear in the View - Folder Views cascade menu. The views for a particular folder appear only when that folder is the current folder. A user must have owner privilege on a folder in order to define and modify its views.

Folder views are stored in the folder itself.

Sticky Views

Sticky views do not appear on any menu; rather, they implement the current view on a folder. When a user modifies a view on a folder, the Exchange Client saves that view in order to associate it with the folder, so that when the user returns to the folder, the same view will reappear.

Sticky views are stored in the default message store, in the IPM_VIEWS folder specified by the PR_VIEWS_ENTRYID property on this store. (This property is valid only if the FOLDER_VIEWS_ENTRYID flag is set in the PR_VALID_FOLDER_MASK property on the store.) This lets every user have a unique sticky view on a public folder common to all users. The sticky view keeps the record key of its target folder as PR_VD_VIEW_FOLDER.

When the user opens a folder, the Exchange Client first looks for a sticky view for that folder; this view will either reference another named view, or else will contain the view descriptor for the view. If no sticky view exists for the folder, Exchange will use the initial view for that folder, as defined by the folder's PR_DEFAULT_VIEW_ENTRYID property. If no such initial view exists, Exchange will use its default Normal view.

Schema of View Descriptors

Table A-4 summarizes the schema of view descriptors.

Name Type ID Description
PR_MESSAGE_CLASS PT_TSTRING 0x001A Distinguishes view descriptors from other messages in the associated contents table. All VDs have message class IPM.Microsoft.FolderDesign.NamedView.
PR_VD_BINARY PT_BINARY 0x7001 All the column definitions for the view, compressed into a single property.
PR_VD_STRINGS PT_TSTRING 0x7002 The display names for all the column definitions for the view, compressed into a single property.
PR_VD_FLAGS PT_LONG 0x7003 Flags global to the entire view descriptor.
PR_VD_LINK_TO PT_BINARY 0x7004 If set, the long-term entry identifier of the view descriptor to use. Used for sticky views referencing existing named views.
PR_VD_VIEW_FOLDER PT_BINARY 0x7005 The record key of the folder to which this view applies.
PR_VD_NAME PT_TSTRING 0x7006 The display name of this view.
PR_VD_VERSION PT_LONG 0x7007 Version of the view descriptor schema. Must have value 8.
PR_VD_COLLAPSE_STATE PT_BINARY 0x7008 The expand/collapse state of the view on the current folder.

Table A-4 Schema of view descriptors. Conjoin the values in the second and third columns with the PROP_TAG macro to create a tag for each of these properties. Note that PR_MESSAGE_CLASS is standard.

Message class

Every view descriptor has the message class IPM.Microsoft.FolderDesign.NamedView, distinguishing it from other messages in the associated contents table of a folder, such as form definition messages.

PR_VD_BINARY

The view descriptor compresses all its column definitions into a single binary property. The next section (Cracking the View Streams) calls this the binary view stream.

PR_VD_STRINGS

The view descriptor compresses all displayable strings associated with its column defintions into a single string property. The next section (Cracking the View Streams) calls this the string view stream.

PR_VD_FLAGS

Bit 0x00000010 in this flags property indicates that the view does not use its own view definition, but instead references the view definition of another view via the PR_VD_LINK_TO property. This allows a user to set a named view on a folder as a sticky view.

#define VDF_LINK 0x00000010


As of August 1996, Microsoft had not publically defined any other fields in this property. Leave them alone.


PR_VD_LINK_TO

When a view has VDF_LINK set in its flags property, this property contains the long-term entry identifier of the view descriptor for the referenced named view.

PR_VD_VIEW_FOLDER

Common views, personal views, and sticky views all reside in a folder other than that to which they apply. This property names the target folder for such views, specifying it as a MAPI record key.

PR_VD_NAME

Every view has a display name, appearing in cascades beneath the View menu and elsewhere in the user interface.

PR_VD_VERSION

By embedding a version number in the view descriptor, the Exchange Client protects application code from damaging view descriptors created by potential future versions of Exchange. The schema described in this document, and as created by versions 4.0 and 4.1 of the Exchange Client, has version number 0x00000008.


Never read or write a view descriptor with an unrecognized version number.


PR_VD_COLLAPSE_STATE

For a categorized view, Exchange keeps the expand/collapse state of the viewed contents table in this property. This is the value retrieved by IMAPITable::GetCollapseState and set by IMAPITable::SetCollapseState.

Cracking the View Streams

The view descriptor encodes most of its information into two stream-style properties, the binary view stream (PR_VD_BINARY) and the string view stream (PR_VD_STRINGS). In order to create or manipulate a view, application code must read and write this stream format. Since these two properties are streams, application code must read and write them serially.

The VD Structure

The first block of data in the binary view stream is the VD structure.

struct VD
{
	ULONG ulReserved1
	ULONG ulReserved2
	ULONG ulVersion;
	ULONG ulReserved3;
	ULONG ulReserved4;
	ULONG cvcd;			// # of VCDs
	ULONG ivcdSort;		// VCD to sort
	ULONG cCat; 			// # of categorized columns
	ULONG ulCatSort;		// Sort order for categorized columns
	ULONG ulReserved5;
	ULONG ulReserved6;
	ULONG ulReserved7;
	ULONG ulReserved8;
	ULONG ulReserved9;
	ULONG ulReserved10;
};

Applications must zero all reserved fields in this structure.

ulVersion

A version number, which must match the value in PR_VD_VERSION.

cvcd

Count of view column descriptors (VCDs) in the rest of the binary view stream.

ivcdSort

0-based index in the pending VCD sequence of the VCD defining the column to use for sorting the view.

cCat

Count of categorized columns in the view, or 0 if the view is not categorized at all.

ulCatSort

Sort order flags for the categorized columns. The most significant bit is the sort order flag for the highest level (leftmost) grouping in the viewer; the 2nd most significant bit is the sort order for the 2nd highest level grouping, etc. The flag is set for descending sort orders and cleared for ascending sort orders.

The VCD structures

Immediately following the VD structure in the binary stream come the VCD structures, specifying the columns in the view. The total count of VCDs appeared in the preceding VD structure.

struct VCD
{
	ULONG vcds;
	ULONG cx;
	ULONG ulReserved1;
	ULONG ulFlags;
	ULONG ulReserved2;
	ULONG ulReserved3;
	MAPINAMEID mnid;
};

Each VCD structure appears in the stream interleaved with other information for the VCD. If the VCD specifies a MAPI named property by having VCDF_NAMEDPROP set in its flags field, the GUID for that named property will immediately follow the VCD in the binary view stream; the application reading and writing the VCD must set the subfield within the MAPINAMEID field from this value. Furthermore, if that named property has a string identifier, as noted by the ulKind field within the named property structure, the Unicode string will immediately follow the GUID in the binary view stream; again, the application must marshall and unmarshall this value as necessary to build a VCD from the data in the stream.

After reading the VCD structure from the binary view stream, an application should read the display name for that column from the accompanying string view stream.

vcds

Identifies the property that the view will display in this column. (VCDS denotes "view column descriptor selector.") For most columns this is simply the property tag of the desired property; however, PROP_TAG( PT_NULL, 0x0004) encodes a blank column, and PROP_TAG( PT_NULL, 0x0005) the action-icon column used in remote viewers. Table A-5 lists common VCDS values, together with the view column descriptor flags that Exchange applies by default to each value.

cx

Column width, specified in characters or pixels. If the VCD has the flag VCDF_BITMAP set, the width is considered in pixels.


Always specify widths in characters wherever possible. This makes views less dependent on the fonts installed on a particular client workstation.


ulFlags

View column descriptor flags, as listed in Table A-6.

Reserved fields

As with the VD structure, applications should zero reserved fields.

View column descriptor selector Default cx Default flags
PROP_TAG( PT_NULL, 0x0004) (Blank "drag column," must be first) 7 BITMAP, NO_CUSTOM, NOT_SORTABLE
PROP_TAG( PT_NULL, 0x0005) (Action icon) 20 BITMAP, CENTER_JUSTIFY, SORTDESCENDING, SORTDLG, RCOLUMNSDLG
PR_IMPORTANCE 10 BITMAP, CENTER_JUSTIFY, SORTDESCENDING, MOVEABLE, COLUMNSDLG, SORTDLG, GROUPDLG, RCOLUMNSDLG
PR_SENSITIVITY 20 LEFT_JUSTIFY, SORTASCENDING, MOVEABLE,

COLUMNSDLG, SORTDLG, GROUPDLG, RCOLUMNSDLG

PR_MESSAGE_CLASS 20 BITMAP, CENTER_JUSTIFY, SORTASCENDING, MOVEABLE, COLUMNSDLG, SORTDLG, GROUPDLG, RCOLUMNSDLG
PR_HASATTACH 13 BITMAP, CENTER_JUSTIFY, SORTDESCENDING, MOVEABLE, COLUMNSDLG, SORTDLG, GROUPDLG, RCOLUMNSDLG
PR_SENT_REPRESENTING_NAME ("Sender") 23 LEFT_JUSTIFY, SORTASCENDING, MOVEABLE,

COLUMNSDLG, RCOLUMNSDLG, SORTDLG, GROUPDLG

PR_DISPLAY_TO 20 LEFT_JUSTIFY, SORTASCENDING, MOVEABLE, COLUMNSDLG, SORTDLG, GROUPDLG, RCOLUMNSDLG
PR_SUBJECT 39 LEFT_JUSTIFY, SORTASCENDING, MOVEABLE,

COLUMNSDLG, SORTDLG, GROUPDLG, RCOLUMNSDLG

PR_MESSAGE_DELIVERY_TIME ("Received") 26 LEFT_JUSTIFY, SORTDESCENDING, MOVEABLE,

COLUMNSDLG, SORTDLG, GROUPDLG, RCOLUMNSDLG

PR_CLIENT_SUBMIT_TIME ("Submit time") 26 LEFT_JUSTIFY, SORTDESCENDING, MOVEABLE,

COLUMNSDLG, SORTDLG, GROUPDLG

PR_MESSAGE_SIZE 9 RIGHT_JUSTIFY, SORTDESCENDING, MOVEABLE,

COLUMNSDLG, SORTDLG, GROUPDLG, RCOLUMNSDLG

PR_DISPLAY_NAME 60 LEFT_JUSTIFY, SORTASCENDING
PR_MESSAGE_DOWNLOAD_TIME ("Count time") 18 RIGHT_JUSTIFY, SORTDESCENDING, SORTDLG, RCOLUMNSDLG
PR_BODY 20 LEFT_JUSTIFY, SORTASCENDING, MOVEABLE,

COLUMNSDLG, SORTDLG, GROUPDLG

PR_PARENT_DISPLAY ("In Folder" in search viewers) 20 LEFT_JUSTIFY, SORTASCENDING, MOVEABLE,

COLUMNSDLG, SORTDLG, GROUPDLG

PR_CONVERSATION_TOPIC 20 LEFT_JUSTIFY, SORTASCENDING,MOVEABLE, COLUMNSDLG, SORTDLG,GROUPDLG
PR_CONVERSATION_INDEX 1 BITMAP, NO_CUSTOM, SORTDLG

Table A-5. Some common view column descriptor selectors and their default attributes.

Flag Value Meaning
VCDF_BITMAP 0x00000008 Set when the column width value is measured in pixels.
VCDF_NOT_SORTABLE 0x00000020 Set if the column cannot specify a sort.
VCDF_SORTDESCENDING 0x00000040 Set for a column whose default is to sort in descending order. When clear, the default is ascending order.
VCDF_MOVABLE 0x00000100 Set if the column can be moved relative to other columns in the view.
VCDF_COLUMNSDLG 0x00000200 Set when the column is applicable to the column dialog.
VCDF_SORTDLG 0x00000400 Set when the column is applicable to the sort dialog.
VCDF_GROUPDLG 0x00000800 Set when the column is applicable to the group dialog.
VCDF_NAMEDPROP 0x00001000 Set when mnid contains a named MAPI property to be displayed in the column. This also requires reading the named property information from the binary view stream.
VCDF_RCOLUMNSDLG 0x00002000 Set when the column is applicable to the remote columns dialog.
VCDF_MULTIVALUED 0x00004000 Set when the column contains a multivalued property.

Table A-6 View column descriptor flags

The row restriction

Following all VCD definitions in the binary and string view streams, the view specifies the restriction to apply to the rows of the contents table. A restriction is specified as a MAPI SRestriction structure, flattened onto the two streams of the view. Reading a restriction is a recursive operation, as befits the recursive nature of a SRestriction. The topmost node in the restriction always has type RES_COMMENT.

Reading one node of the restriction

To read a node of the restriction, read sizeof(SRestriction) bytes off of the binary view stream. The value found in restriction type field rt will specify what subsequent reads to make in order to unmarshall the restriction structure completely.

Reading a property of the restriction

To read a set of properties of the restriction, first read a ULONG off of the binary view stream. This specifies the count of the number of properties to read. Next, read a vector of that many SPropValue structures off of the binary view stream. For each entry in the resulting vector, the property value type field will specify what subsequent reads to make in order to unmarshall the property structure completely.

For more information

Check the Microsoft FTP server for more information on internal Microsoft Exchange formats: ftp://ftp.microsoft.com/developr/MAPI. My WWW site may also contain additional samples and information: http://www.angrygraycat.com/goetter/book/.


Other destinations

Book
Go to the main page for this book
Ben Goetter
Go to the author's personal home page
Site Map
Find your way around this site

Originally written: 13 August 1996
Published on WWW: 3 October 1996
Last modified: 13 August 1998

Ben Goetter (contact information)

Copyright 1996-1998 Ben Goetter. All rights reserved.