New Outlook Documentation Part 2 – Cached Mode Headers


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

Using the Appropriate Interface to Manage Messages in an OST in Cached Exchange Mode

INTRODUCTION

The following article provides information when using Microsoft Collaboration Data Objects (CDO)and how to manage messages in an Offline Store (OST) while the client is in Cached Exchange mode.

MORE INFORMATION

When in cached Exchange mode, messages in the OST can be in one of two states:

  • A message in its entirety – with the header and body.
  • A message with only its header downloaded.

Use the IID_IMessageRaw GUID when requesting an IMessage interface for a message in an OST while in cached Exchange mode. Using the IID_IMessage GUID to request an IMessage interface on a message that has only its header downloaded will force a synchronization that will attempt to download the entire message.

Using IID_IMessageRaw and IID_IMessage to request an IMessage interface will return interfaces that are identical in use. The only difference is that the IMessage interface requested with IID_IMessageRaw will return an email message as it exists in the OST, without forcing synchronization.

If OpenEntry returns the error code, MAPI_E_INTERFACE_NOT_SUPPORTED, then the message store does not support accessing the message in raw mode. In this case attempt OpenEntry again passing IID_IMessage.

Note: While cached mode is similar to remote mail headers as used in classic offline mode, the default behavior is different. Remote mail header messages are not downloaded when accessed. This GUID will not work with remote mail headers.

Definition of IID_IMESSAGE_RAW

#if !defined(INITGUID) || defined(USES_IID_IMessageRaw)
DEFINE_OLEGUID(IID_IMessageRaw, 0x0002038A, 0, 0);
#endif

 

Usage

When calling OpenEntry, pass IID_IMessageRaw instead of IID_IMessage. The following code sample illustrates the usage:

HRESULT HrOpenRawMessage
(
   LPMDB lpMSB, 
   ULONG cbEntryID, 
   LPENTRYID lpEntryID, 
   ULONG ulFlags, 
   LPMESSAGE* lpMessage
)
{
   ULONG ulObjType = NULL;

   HRESULT hRes = lpMDB->OpenEntry(
      cbEntryID,
      lpEntryID,
      IID_IMessageRaw,
      ulFlags,
      &ulObjType,
      (LPUNKNOWN*) lpMessage));

   return hRes;
}
Comments (16)

  1. Hi Stephen,

    what about transport providers in Outlook 12? I’ve try pre beta and I’ve found serious changes. Can you give the answer what happens with MAPI in Outlook 12?

    Alexander Gorlach,

    http://www.mapilab.com/

    gorlach@thesamedomain

  2. Stephen Griffin says:

    I’ll contact you offline as this is offtopic for this post.

  3. Simon Audet says:

    Hi Stephen,

    Asking for IMessageRaw with id received from the an advise sink seems to make the message "unreachable" after the call to IMapiSession.OpenEntry w/ given entry id.

    Do you have any clue on this.

  4. Stephen Griffin says:

    What do you mean by "unreachable"? Are you getting an error code?

  5. Simon Audet says:

    That was caused by the fact the id I was asking for was given to me by a store notification.  I implemented table notifications instead of store notifications and everything is smooth!

  6. wzhao2000 says:

    Hi, Steve,

    It seems there is an MSKB article about "dispidHeaderItem" field (#912239). Are they somehow related? The article didn’t mention about IID_IMessageRaw, but I guess the LPMESSAGE pointer should be obtained via IID_IMessageRaw interface, otherwise a full sync will be forced, which will defeat the purpose of this field. Or this "dispidHeaderItem" property is intend to be used as a folder table column for fast outcome?

  7. Stephen Griffin says:

    dispidHeaderItem applies to POP3 and IMAP. IID_IMESSAGE_RAW applies to cached mode. They’re not related.

  8. Gev says:

    Hi Steve

    This article partialy answered my question, but yet didn’t solve my issue. What about Outlook 2007?

    I’m using Exchange client extensions and for messages being veiwed I have to temporary change the message body without saving changes in message. To do that I was calling the HrGetOneProp from IExchExtMessageEvents::OnRead() to get PR_BODY_HTML property, replace the Value.lpszA pointer with pointer to my string and then call HrSetOneProp to set it back. This worked just fine until setting Outlook to work in cached Exchange mode. In this mode none of those calls return error and everything seems to be fine, but the set does not actually change the message body. I’ve got this same result on both Windows XP + Outlook 2007 with all the windows and office updates installed and Win 2003 Server with Outlook 2007.

    I’ve tried to change HrGetOneProp/HrSetOneProp IMAPIProp::GetProps/IMAPIProp::SetProps but it didn’t help at all even if I use this ID,  though it seems the MAPI version I have does not support it. Should it work the same way with Outlook 12? I tried to use th IID_IMessageRaw, but got undeclared identifier compilation error. Then I tried to import the definition of IID_IMessageRaw from this article, but then it gave me unresolved external  so I had to also add definietion of DEFINE_GUID macro in my sources from guiddef.h. This helped with compilation errors, but didn’t help with my problem and message content is not being changed.

    I also found this article: http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b834496 which recommends to use the MAPI_NO_CACHE macro to open entries synchronised, but it seems my MAPI does not support it either.

    Sorry for long question and thanks in advance.

  9. Stephen Griffin says:

    It sounds like at the point where you’re making your change, Outlook has already read the stream. Or – Outlook has a different copy of the message open than the one you’re working on. How did you open the message? Was it passed to you or did you open it with OpenEntry. If you opened it yourself, you can’t expect your uncommited changes to be visible to anyone but you.

  10. Gev says:

    Steve

    Thanks for your prompt reply.

    To use the IID_IMessageRaw I actually do open message myself with OpenEntry so thanks for cutting the wrong path off.

    But in original version which worked with cachedExchange Mode turned off I used the message returned by the IExcExtCallback::GetObject() from the pointer to IExcExtCallback interface passed to IExchExtMessageEvents::OnRead(). Why should cahced Exchange mode make difference anyway?

    I’m doing this from IExchExtMessageEvents::OnRead() so at this point Outlook definitely didn’t read the message properties yet (or at least that’s how the doc says).

    For a moment I thought that it is possible that after Outlook calls OnRead and the synchronizes with Exchange server by so overriding my changes in the message body, but this is not the case since even in offline mode my changes to the message make no effect.

    I’ve found another article (http://support.microsoft.com/kb/832355) on Outlook 2003 problem, which in particular says about third-party CryptoEx security add-in used to encrypt/sign messages and "When the CryptoEx Outlook security add-in program tries to replace the original encrypted or signed e-mail message body with the decrypted content, the call is unsuccessful, and the e-mail message body appears to be empty"(quotation from MSKB site) when Outlook is in cached Exchange mode. To fix this Microsoft has produced some hotfix which later was included in SP1 for Office 2003.

    Right now I can’t say if this the case with my add-in and since in Outlook 2003 I used the different technique to change message body which is impossible to use in 2007 due to Microsoft’s desision to not use IE to render html content, but I’m going to backport my changes and try this with Outlook 2003. Any chances this issue is back and alive in Outlook 2007?

    Thanks again,

    Gev

  11. Gev says:

    Stephen

    I was able to get the same failure on Outlook 2003 even with Office 2003 SP2. In general is there any reason why HrSetOneProp should fail when Outlook is configured in cached Echange mode?

  12. Stephen Griffin says:

    Gev,

    I don’t work much with add-ins since leaving developer support, but I discussed your issue with some of my colleagues. One of them pointed out that the problem may not be cached mode, per se, but instead with the PST provider, on which caced mode is built.

    So – to test this theory – try your code out with a PIM or Internet profile, using just the PST as your store. Do you see the same behavior?

    Steve

  13. Gev says:

    Stephen

    I was busy with other tasks last month so couldn’t reply you earlier. Unfortunately the optimal solution for my issue would be changing as little source as possible. Also this add-in MUST run with Exchange server so trying PIM or Internet profile won’t help much, even if it will work.

    In general if youdon’t work much with add-ins, could you please point me right blog/forum to ask my question? Sorry if this is completely offtop.

    Thank you for all your help

    Gev

  14. Stephen Griffin says:

    You completely missed my point – you need to *try* it with the PIM/Internet profile to see whether the problem is in cached mode or if it’s in the PST provider. That’ll dictate the next steps. This is troubleshooting 101 – learn as much as you can about the problem.

  15. Gev says:

    Sorry that..

    I’ve tried with Internet mail profile storing messages in .pst file, and the HrSetOneProp worked fine. I guess this confirms that the problem is in cached mode right?

  16. Stephen Griffin says:

    Gev – you’ll need to open a case with support. I can’t work an issue like this through blog comments.