Fastest Shutdown In The West

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

I previously wrote about some changes the development team had in mind for Outlook 2007 SP2 in the area of shutdown. The change discussed there, known as Shutdown With External References, allows Outlook to shut down completely even if there are outstanding Object Model references. The second major improvement in shutdown is known as Fast Shutdown, which allows a MAPI client such as Outlook to signal to the providers that a shutdown is imminent. As we get nearer to SP2, I’ve been asked to provide documentation on the APIs which MAPI client and provider developers can use to ensure the best possible experience with Fast Shutdown.

What is Fast Shutdown?

The intent of Fast Shutdown is to do the minimal amount of work required to persist MAPI data and settings, and then exit the client immediately. It is preferable to forego any cleanup action that the OS will take care of once the process is gone (releasing handles, freeing allocations, closing network sockets, etc.). However, it is the client’s and provider’s responsibility to ensure any unsaved data or settings are persisted once shutdown begins.

While Fast Shutdown will affect every MAPI session within the process in which it is called, Fast Shutdown will not affect MAPI sessions in other processes, including any shared sessions. Two processes holding a shared session which both want Fast Shutdown should both call Fast Shutdown from within their own process. It is okay, though, for one process to use Fast Shutdown while the other process does not. When Fast Shutdown is requested, MAPI will check for Fast Shutdown support on every loaded provider (address book, transport, message store). If any currently loaded provider does not support Fast Shutdown, a traditional shutdown will be required.

There are two main aspects of the Fast Shutdown API. The first is an interface a client can utilize to initiate a fast shutdown. The second is an interface a provider can implement to indicate support for fast shutdown.

MAPI Client Shutdown Interface
A client wishing to initiate Fast Shutdown will query for the the IMAPIClientShutdown interface off of any IMAPISession object it holds. After obtaining the interface, the client can call QueryFastShutdown to see if a Fast Shutdown is supported. The client can also call NotifyProcessShutdown to indicate that it’s planning to shutdown soon. This can be called regardless of whether QueryFastShutdown indicates Fast Shutdown support. If Fast Shutdown is supported, the client can call DoFastShutdown to force MAPI to quickly and safely tear down.

Note that once DoFastShutdown is called, you shouldn’t make any more MAPI calls – not even MAPIUninitialize. Continuing to use MAPI after a call to DoFastShutdown could lead to undefined behavior. Also, no add-in for Outlook should call any of the client shutdown functions from within the Outlook process. Outlook will call DoFastShutdown on its own as needed during shutdown.

 #if !defined(INITGUID) || defined(USES_IID_IMAPIClientShutdown)
DEFINE_OLEGUID(IID_IMAPIClientShutdown, 0x00020397, 0, 0);

#endif
DECLARE_MAPI_INTERFACE_PTR(IMAPIClientShutdown, LPMAPICLIENTSHUTDOWN);

#define MAPI_IMAPICLIENTSHUTDOWN_METHODS(IPURE) \
  MAPIMETHOD(QueryFastShutdown) \
      (THIS) IPURE; \
  MAPIMETHOD(NotifyProcessShutdown) \
      (THIS) IPURE; \
  MAPIMETHOD(DoFastShutdown) \
      (THIS) IPURE;
DECLARE_MAPI_INTERFACE_(IMAPIClientShutdown, IUnknown)
{
  BEGIN_INTERFACE 
  MAPI_IUNKNOWN_METHODS(PURE)
  MAPI_IMAPICLIENTSHUTDOWN_METHODS(PURE)
};

IMAPIClientShutdown:IUnknown
This interface is designated IID_IMAPIClientShutdown and is obtained by calling QueryInterface on any IMAPISession object. That single interface instance is used to control the rest of the shutdown process for all MAPI sessions held by that process. The interface has three functions:

HRESULT QueryFastShutdown()

Clients call this function to query MAPI for Fast Shutdown support. This function returns S_OK if MAPI is able to support Fast Shutdown; otherwise, it returns MAPI_E_NO_SUPPORT (or any other error code). Once MAPI returns a success/failure, that state cannot change for the remainder of the current process’s lifetime. MAPI will iterate through all open MAPI sessions for that process and, for each session, will query each loaded provider for Fast Shutdown support. An error will be returned if any single currently loaded provider does not support Fast Shutdown. A provider that is unaware of the Fast Shutdown APIs is not considered to support FastShutdown.

HRESULT NotifyProcessShutdown()

Clients indicate the intent to shutdown the process. This may be called regardless of whether Fast Shutdown is supported. MAPI will notify all providers that expose IMAPIProviderShutdown.

HRESULT DoFastShutdown()

Clients indicate MAPI should shut down immediately. MAPI will iterate through all open MAPI sessions for that process and, for each session, notify each loaded provider to execute Fast Shutdown.

MAPI Provider Shutdown Interface
Providers wanting to support fast shutdown need to implement the IMAPIProviderShutdown interface. When a client calls IMAPIClientShutdown::QueryFastShutdown, MAPI will iterate through all open sessions and, for each session, all registered providers to query for the IMAPIProviderShutdown interface and call QueryFastShutdown. MAPI will always query and notify providers through this interface within each MAPI session in the following order:

  1. Transport providers
  2. Address Book providers
  3. Store providers

For example, when a transport provider is shutting down, it can rely on an operational store provider.

MAPI may call a provider’s NotifyProcessShutdown method to indicate that a process shutdown is forthcoming. This may be called regardless whether the provider indicates Fast Shutdown support. The provider can expect MAPI to either perform a normal shutdown or call DoFastShutdown.

MAPI may call a given provider multiple times if there are multiple stores open that are serviced by the same provider.

 #if !defined(INITGUID) || defined(USES_IID_IMAPIProviderShutdown)
DEFINE_OLEGUID(IID_IMAPIProviderShutdown, 0x00020398, 0, 0);

#endif
/* IMAPIProviderShutdown Interface --------------------------------------- */

DECLARE_MAPI_INTERFACE_PTR(IMAPIProviderShutdown, LPMAPIPROVIDERSHUTDOWN);
#define MAPI_IMAPIPROVIDERSHUTDOWN_METHODS(IPURE) \
  MAPIMETHOD(QueryFastShutdown) \
      (THIS) IPURE; \
  MAPIMETHOD(NotifyProcessShutdown) \
      (THIS) IPURE; \
  MAPIMETHOD(DoFastShutdown) \
      (THIS) IPURE;
DECLARE_MAPI_INTERFACE_(IMAPIProviderShutdown, IUnknown)
{
  BEGIN_INTERFACE 
  MAPI_IUNKNOWN_METHODS(PURE)
  MAPI_IMAPIPROVIDERSHUTDOWN_METHODS(PURE)
};

IMAPIProviderShutdown:IUnknown

This interface is designated IID_IMAPIProviderShutdown and is obtained by MAPI calling QueryInterface on the provider object (IE, either IXPProvider, IABProvider, or IMSProvider). This interface exposes the functionality required to support Fast Shutdown at the provider level. The interface has three functions:

HRESULT QueryFastShutdown()

The provider returns S_OK if it supports Fast Shutdown for the current session; otherwise, it returns MAPI_E_NO_SUPPORT (or any other error code). Once a provider returns a success/failure, that state cannot change for the remainder of the provider’s lifetime.

HRESULT NotifyProcessShutdown()

MAPI indicates that a process shutdown is planned. The provider should shut down everything that is non-essential to saving data to its primary data store. If a provider locally caches data from a server, it might choose to immediately disconnect to facilitate a faster shutdown once requested.

For example, a transport provider may stop unnecessary background operations that are checking for new mail. An address book provider might stop downloading recent changes from its server. A store provider might stop maintenance tasks, such as compaction or indexing.

It is important to note that actions that a provider takes here may be irreversible for the current lifetime of the MAPI client. For example, once network connections are severed, they cannot be reestablished until the MAPI client restarts.

HRESULT DoFastShutdown()

The provider should immediately shut down without causing data loss. Upon returning, MAPI assumes that the provider is prepared for an immediate process termination.

Registry Keys

We’ve put a couple registry keys in place to help out if Shutdown With External References or Fast Shutdown is causing a problem.

The first was already discussed on Ryan’s Blog:

[HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Outlook\Options\Shutdown]
"AllowShutdownWithExternalReferences"=dword:00000000

Setting the key to 0 disables the behavior Ryan discussed. The default setting is 1, which allows Outlook to shutdown with external references.

The second key tells Outlook not to call DoFastShutdown:

[HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Outlook\Options\Shutdown]
"DisableFastShutdown"=dword:00000001

Setting the key to 1 disables Outlook’s call to DoFastShutdown. The default setting is 0, which allows Outlook to call DoFastShutdown.