• Sign in
 
  •  
  • MSDN Blogs
  • Microsoft Blog Images
  • More ...

  • About
  • Email Blog Author
  • RSS for posts
  • Atom
  • RSS for comments
    • OK
  • CDO (25)
  • Code Snippet (43)
  • Custom Providers (17)
  • Debugging (7)
  • DevMsgTeam (301)
  • Documentation (109)
  • DST (8)
  • EWS (7)
  • Exchange (109)
  • Gotchas (97)
  • Hotfix (28)
  • MAPI (240)
  • MAPI Download (54)
  • MFCMAPI (101)
  • MSDN (59)
  • Non Dev (11)
  • OOM (17)
  • Outlook (171)
  • Outlook 2007 Auxiliary Reference (45)
  • Outlook Integration API (12)
  • Protocol Docs (20)
  • PST/OST (23)
  • Referrals (8)
  • Vista (12)
  • WrapPST (18)
Links:
  • Download MFCMAPI
  • MFCMAPI on Facebook
  • Troubleshooting Outlook Crashes
  • Office Update Center
  • Developer Messaging Team Blog
This site is provided "AS IS" with no warranties, and confers no rights. Use of included code samples are subject to the terms specified in the Terms of Use.
Archives
  • May 2013 (3)
  • April 2013 (1)
  • March 2013 (2)
  • February 2013 (2)
  • January 2013 (2)
  • December 2012 (4)
  • November 2012 (2)
  • October 2012 (2)
  • September 2012 (1)
  • August 2012 (3)
  • June 2012 (2)
  • May 2012 (1)
  • April 2012 (3)
  • March 2012 (3)
  • February 2012 (3)
  • January 2012 (1)
  • December 2011 (3)
  • November 2011 (1)
  • October 2011 (3)
  • September 2011 (1)
  • August 2011 (1)
  • July 2011 (4)
  • June 2011 (3)
  • May 2011 (3)
  • April 2011 (3)
  • March 2011 (5)
  • February 2011 (1)
  • January 2011 (2)
  • December 2010 (1)
  • November 2010 (4)
  • October 2010 (1)
  • September 2010 (3)
  • August 2010 (5)
  • July 2010 (3)
  • June 2010 (3)
  • May 2010 (1)
  • April 2010 (3)
  • March 2010 (3)
  • February 2010 (3)
  • January 2010 (2)
  • December 2009 (3)
  • November 2009 (5)
  • October 2009 (4)
  • September 2009 (5)
  • August 2009 (5)
  • July 2009 (11)
  • June 2009 (6)
  • May 2009 (5)
  • April 2009 (3)
  • March 2009 (18)
  • February 2009 (10)
  • January 2009 (3)
  • December 2008 (2)
  • November 2008 (2)
  • October 2008 (5)
  • September 2008 (4)
  • August 2008 (10)
  • July 2008 (6)
  • June 2008 (8)
  • May 2008 (2)
  • April 2008 (4)
  • March 2008 (2)
  • February 2008 (2)
  • January 2008 (5)
  • December 2007 (3)
  • November 2007 (2)
  • October 2007 (3)
  • September 2007 (1)
  • August 2007 (4)
  • July 2007 (5)
  • June 2007 (3)
  • May 2007 (4)
  • April 2007 (1)
  • March 2007 (6)
  • February 2007 (3)
  • January 2007 (2)
  • December 2006 (4)
  • November 2006 (3)
  • October 2006 (1)
  • August 2006 (1)
  • June 2006 (5)
  • May 2006 (5)
  • December 2005 (1)
  • November 2005 (4)
  • October 2005 (2)
  • September 2005 (1)
  • April 2005 (3)
  • December 2004 (2)
  • September 2004 (2)
  • August 2004 (3)
  • July 2004 (3)
Blogs I Read
  • Exchange

  • Raymond Chen [MSFT]

  • Larry Osterman [MSFT]

  • Peter David

  • Aaron Margosis [MSFT]

  • Jason Johnston [MSFT]

  • Matt Stehle (MSFT)

  • Patrick Creehan [MSFT]

  • Ryan Gregg [MSFT]

    Outlook PM
  • WebDav 101

    Dan Bagley (MSFT)
  • Dave Vespa [MSFT]

  • Randy Topken

    Outlook EE

September, 2005

MSDN Blogs > SGriffin's MAPI Internals > September, 2005
  • Subscribe via RSS
Sort by: Most Recent | Most Views | Most Comments
Excerpt View | Full Post View
  • SGriffin's MAPI Internals

    Outlook 2003 Integration API Wrapped PST Docs and Sample

    Posted over 8 years ago
    by Stephen Griffin - MSFT
    • 46 Comments

    [This is now documented here: http://msdn.microsoft.com/en-us/library/bb821132.aspx]

    [This sample is now part of the Outlook MAPI Code Samples!]

    In the Outlook 2003 Integration API, we documented the Replication API. This is a nifty API for implementing replication between a wrapped PST and your own custom back end, which should be a great way to simplify implementation of a MAPI Message Store Provider without incurring all the pain involved in writing one from scratch. Unfortunately, we neglected to document how to create a wrapped PST. This documentation (which should eventually be part of the MSDN) corrects this oversight. Much thanks to Fergus Wilson of Meridio for his assistance in testing this sample.

    Please post back any problems you encounter with this sample or the docs so I can correct them. Thanks!

    The sample code can be downloaded here: http://stephengriffin.members.winisp.net/wrappst/wrappst.zip

    Wrapping the PST provider in preparation for using the Replication API
    The Replication API can only be used in conjunction with a Wrapped PST provider. This document defines a Wrapped PST provider and gives instructions for constructing one.

    Wrapped PST Provider:
    A wrapped PST provider is a custom MAPI message store provider which uses the PST provider as the back end for storing data. Most functions in a basic wrapped PST provider will proxy their arguments directly to the underlying PST provider. This allows the developer doing the wrapping to focus on the portions of the provider specific to their business needs without needing to invest time in writing a store provider from scratch.

    Some functions and classes do need special logic in them to inform the PST provider that it has been wrapped so the Replication API can function. This document outlines what needs to be done in these functions.

    The remaining code in a wrapped PST can be used to change default behavior, such as supporting additional properties not native to a PST by overriding GetProps, or allowing OpenEntry to do special processing on a message before handing it back to the client.

    Constants:
    The following constants are used in this documentation. Note that some changes and clarifications have been made to the constant definitions given in the Replication API.

    #define MDB_OST_LOGON_UNICODE ((ULONG) 0x00000800)
    #define MDB_OST_LOGON_ANSI    ((ULONG) 0x00001000)
    
    // OffLineFileInfo
    typedef struct {
    	ULONG    ulVersion;     // Structure version
    	MAPIUID  muidReserved;
    	ULONG    ulReserved;
    	DWORD    dwAlloc;       // Number of primary source keys
    	DWORD    dwReserved;
    	LTID     ltidReserved1;
    	LTID     ltidReserved2;
    } OLFI;
    
    #define PR_OST_OLFI PROP_TAG(PT_BINARY, 0x7C07)
    #define OLFI_VERSION 0x01
    
    // UID of an NST provider
    const MAPIUID g_muidProvPrvNST =
    	{ 0xE9, 0x2F, 0xEB, 0x75, 0x96, 0x50, 0x44, 0x86,
    	  0x83, 0xB8, 0x7D, 0xE5, 0x22, 0xAA, 0x49, 0x48 };
    
    // This is a clarification of the definitions of PXIHC and PXICC 
    // mentioned in the Replication API
    DECLARE_MAPI_INTERFACE_PTR(IExchangeImportHierarchyChanges,PXIHC);
    DECLARE_MAPI_INTERFACE_PTR(IExchangeImportContentsChanges,PXICC);
    
    // It is essential that the FEID, MEID and SKEY structures
    // be wrapped in this pack pragma or they will be the wrong size
    #pragma pack(1)
    
    struct FEID
    {
    	BYTE	abFlags[4];
    	MAPIUID	muid;
    	WORD	placeholder;
    	LTID	ltid;
    };
    
    struct MEID
    {
    	BYTE	abFlags[4];
    	MAPIUID	muid;
    	WORD	placeholder;
    	LTID	ltidFld;
    	LTID	ltidMsg;
    };
    
    struct SKEY
    {
    	GUID	guid;
    	BYTE	globcnt[6];
    };
    
    #pragma pack()

    MSProviderInit
    This is the entry point when your provider is being loaded by Outlook. Any message store provider needs to implement this function and expose it as an entry point in the store provider’s DLL. This is a well known function name which does not change.

    Implementation:

    • Save off the MAPI memory management routines and be sure to use them when managing MAPI memory.
    • Use GetProcAddress to load the “MSProviderInit” function out of MSPST32.dll.
    • Call the PST’s MSProviderInit with all the same parameters that were passed in, with the exception of the HINSTANCE parameter. This needs to be the handle of MSPST32.dll as returned by LoadLibrary.
    • Wrap the returned LPMSPROVIDER in your own implementation and return it. See CMSProvider.

    ServiceEntry
    This is the entry point when your provider is being configured, such as through the Mail Control Panel. The prototype for this function is MSGSERVICEENTRY, but the name to be used is not mandated. Instead, it is advertised in the PR_SERVICE_ENTRY_NAME property of your profile. In this documentation, we use the name ServiceEntry. Be sure to expose the function as an entry point in the store provider’s DLL.

    Implementation:

    • Call GetMemAllocRoutines off of the passed in LPMAPISUP to get your MAPI memory management routines and be sure to use them when managing memory.
    • The following is for handling MSG_SERVICE_CREATE and MSG_SERVICE_CONFIGURE. Other contexts will require different actions according to the documentation. In particular, MSG_SERVICE_DELETE should be used to perform appropriate cleanup. Contexts which are not implemented can return MAPI_E_NO_SUPPORT.
    • Open the default profile section in which to set our properties using IProviderAdmin::OpenProfileSection, passing NULL for the LMMAPIUID.
    • If cValues and lpProps are both non-null, use SetProps to write them to the profile section.
    • Ensure PR_PROFILE_OFFLINE_STORE_PATH is set in this profile section to the path to your NST file.
    • Ensure PR_MDB_PROVIDER is set in this profile section to g_muidProvPrvNST
    • Wrap the passed in LPMAPISUP in your own implementation. Pass the profile section over to this object. See CSupport.
    • Use GetProcAddress to load the “NSTServiceEntry” function out of MSPST32.dll.
    • Call NSTServiceEntry as follows:
      • Pass the handle to MSPST32.dll in for the HINSTANCE
      • Pass the wrapped support object for LPMAPISUP
      • Use GetProps to get PR_PROFILE_OFFLINE_STORE_PATH and PR_MDB_PROVIDER from the profile section and pass this in for the LPSPropValue parameter
      • Pass NULL for the LPPROVIDERADMIN
    • After calling NSTServiceEntry, finish initializing store properties in the profile. This means
      • Create an EntryID using g_muidProvPrvNST and the path to the store:
        • The size of the entry ID should be 21 bytes plus the length of the path (including file name) plus 1 for the NULL terminator.
        • The first four bytes are NULL..
        • The next 16 are g_muidProvPrvNST.
        • The next byte is NULL.
        • The rest of the entry ID is the path to the store, including the NULL terminator.
      • Wrap it using WrapStoreEntryID with the name of the provider DLL.
      • Get PR_STORE_PROVIDERS from the default profile section and use it to open the store profile section
      • Set the following properties on both the default profile section and on the store profile section:
        • PR_ENTRYID, PR_STORE_ENTRYID: The wrapped EntryID
        • PR_RECORD_KEY: The value of PR_SERVICE_UID from the store profile section
        • PR_STORE_RECORD_KEY, PR_SEARCH_KEY, PR_PROFILE_SECURE_MAILBOX: A UID obtained from IMAPISupport::NewUID (use the same UID for all three properties)
        • PR_PROFILE_USER: The user name. The actual value doesn’t matter as much as the fact that it is set. See IMAPISupport::ModifyStatusRow.

    CMSProvider
    This is the wrapped implementation of IMSProvider. It is required to wrap this interface to provide some special processing needed to make the wrapped PST work.

    Member functions not documented here can just pass their parameters into the underlying wrapped object. The IUnknown functions are implemented normally, making sure that the reference count on the underlying object is maintained.

    The constructor should accept the LPMSPROVIDER object being wrapped.

    The following functions need special handling:
    IMSProvider::Logon

    • An LPMAPISUP object is passed into this function. Wrap this object in your own implementation. Request PR_SERVICE_UID from the default profile section and call OpenProfileSection. Pass the resulting LPPROFSECT into your wrapped support object for later use. See CSupport.
    • Add MDB_OST_LOGON_UNICODE to the set of flags and remove MDB_OST_LOGON_ANSI if it’s there
    • Call the underlying wrapped object’s Logon function with the passed in parameters, the wrapped support object and the modified flags.
    • Set PR_OST_OLFI on the returned LPMDB with an OLFI structure with dwAlloc set to 0x7fffffff
    • [Optional] Wrap the returned LPMDB. This is not strictly required, but this is the entry point into wrapping all objects used by the client.

    IMSProvider::SpoolerLogon

    • An LPMAPISUP object is passed into this function. Wrap this object in your own implementation. Pass in the profile section pointed to by PR_SERVICE_UID on the default profile section.
    • Call the underlying wrapped object’s Logon function with the passed in parameters.

    CSupport
    This is the wrapped implementation of IMAPISupport. It is required to wrap this interface to provide some special processing needed to make the wrapped PST work.

    Member functions not documented here can just pass their parameters into the underlying wrapped object. The IUnknown functions are implemented normally, making sure that the reference count on the underlying object is maintained.

    The constructor should accept the LPMAPISUP object being wrapped and a LPPROFSECT object which will be used in OpenProfileSection.

    The following functions needs special handling:
    IMAPISupport::OpenProfileSection

    When pbNSTGlobalProfileSectionGuid is requested, return the profile section which has been cached in your implementation.

    IMAPISupport::ModifyStatusRow

    The PST provider will attempt to set a status row with PR_IDENTITY_DISPLAY, PR_IDENTITY_ENTRYID, and PR_IDENTITY_SEARCH_KEY. These values will be based on the user specified in PR_PROFILE_USER and assume the user has an EX address type. If this status row is allowed, then later calls to QueryIdentity can fail if no transport can handle this address type. This failure can in turn prevent creation of some items like contacts and appointments. Simply clearing these values will fix this problem. A more advanced fix would be to set a custom status row. Even more advanced would be to wrap the IMSLogon object returned in IMSProvider::Logon to implement a custom or wrapped status entry.

    Using the Replication API
    The documentation of the Replication State Machine describes how to use the API to perform synchronization between an external store and the wrapped PST. See the functions DoSync, SyncDownloadFolders and SyncUploadFolders for sample code illustrating the API.

    [10/6/05 - 10:39 AM] Clarified IMSProvider::Logon

    [10/17/05 - 5:45PM] Added IMAPISupport::ModifyStatusRow, updated sample code

    [11/11/05] Fixed sample URL

Page 1 of 1 (1 items)
  • © 2013 Microsoft Corporation.
  • Terms of Use
  • Trademarks
  • Privacy & Cookies
  • Report Abuse
  • 5.6.426.415