[This is now documented here: http://msdn.microsoft.com/en-us/library/bb820953.aspx]
[This information also published as http://support.microsoft.com/kb/912238]
Just like Cached mode has a way of accessing items in the OST without triggering a download, our IMAP provider has a mechanism for accessing items in the PST without triggering the download. In an ideal world, they'd both use the same mechanism, but nobody's perfect.
Topic A mechanism to manage messages in an IMAP store.
IID_IProxyStoreObject In an IMAP profile, messages in the PST can be in one of two states
Query for this interface to access a function, UnwrapNoRef, which unwraps the IMAP store and allows access to the underlying PST. Without unwrapping, access of a message in the IMAP store can force a synchronization that will attempt to download the entire message. Using the unwrapped store allows access to the message in its current state without triggering this download.
The IMsgStore interface returned by UnwrapNoRef is identical in use to the IMsgStore that was unwrapped. The only difference is that the unwrapped store will return messages as they exist in the PST, without forcing synchronization.
If QueryInterface returns the error MAPI_E_INTERFACE_NOT_SUPPORTED, then the store was not wrapped.
Definition
#define DEFINE_PRXGUID(_name, _l) \ DEFINE_GUID(_name, (0x29F3AB10 + _l), 0x554D, 0x11D0, 0xA9, \ 0x7C, 0x00, 0xA0, 0xC9, 0x11, 0xF5, 0x0A) DEFINE_PRXGUID(IID_IProxyStoreObject, 0x00000000L); #define MAPI_IPROXYSTOREOBJECT_METHODS(IPURE) \ MAPIMETHOD(PlaceHolder1) () IPURE; \ MAPIMETHOD(UnwrapNoRef) (LPVOID *ppvObject) IPURE; \ MAPIMETHOD(PlaceHolder2) () IPURE; DECLARE_MAPI_INTERFACE_(IProxyStoreObject, IUnknown) { BEGIN_INTERFACE MAPI_IUNKNOWN_METHODS(PURE) MAPI_IPROXYSTOREOBJECT_METHODS(PURE) };
Usage Call QueryInterface on the source message store to obtain the IProxyStoreObject interface. Then call UnwrapNoRef to obtain the unwrapped store. Note that UnwrapNoRef does not addref the returned pointer.
HRESULT HrUnWrapMDB(LPMDB lpMDBIn, LPMDB* lppMDBOut) { HRESULT hRes = S_OK; IProxyStoreObject* lpProxyObj = NULL; LPMDB lpUnwrappedMDB = NULL; hRes = lpMDBIn->QueryInterface(IID_IProxyStoreObject,(void**)&lpProxyObj); if (SUCCEEDED(hRes) && lpProxyObj) { hRes = lpProxyObj->UnwrapNoRef((LPVOID*)&lpUnwrappedMDB); if (SUCCEEDED(hRes) && lpUnwrappedMDB) { // UnwrapNoRef doesn't addref, so we do it here: lpUnwrappedMDB->AddRef(); (*lppMDBOut) = lpUnwrappedMDB; } } if (lpProxyObj) lpProxyObj->Release(); return hRes; }
[This is now documented here: http://msdn.microsoft.com/en-us/library/bb820923.aspx]
[This information was also published as http://support.microsoft.com/kb/912239]
This one jumped ahead in the line because Oliver Seaman was asking me about detecting which items are headers. Next post should be about dealing with IMAP header messages.
Topic A property to identify items in header only state
dispidHeaderItem Both Cached Exchange mode and IMAP support the concept of header items. Messages in the Cached Exchange OST and in the IMAP PST can be in one of two states: a message in its entirety with the header and body, or a message with only its header downloaded.
This property can be used to determine the current state of a message.
Note: this property does not apply to remote transport headers, which can be distinguished by the message class “IPM.Remote”.
Definitions
#define dispidHeaderItem 0x8578 DEFINE_OLEGUID(PSETID_Common, MAKELONG(0x2000+(8),0x0006),0,0);
Usage This is a named property of type PT_LONG which will be present and non-zero on a message if the message is a header.
BOOL bIsHeader(LPMESSAGE lpMessage) { HRESULT hRes = S_OK; BOOL bRet = false; ULONG ulVal = 0; LPSPropValue lpPropVal = NULL; LPSPropTagArray lpNamedPropTag = NULL; MAPINAMEID NamedID = {0}; LPMAPINAMEID lpNamedID = NULL; NamedID.lpguid = (LPGUID) &PSETID_Common; NamedID.ulKind = MNID_ID; NamedID.Kind.lID = dispidHeaderItem; lpNamedID = &NamedID; hRes = lpMessage->GetIDsFromNames(1, &lpNamedID, NULL, &lpNamedPropTag); if (lpNamedPropTag && 1 == lpNamedPropTag->cValues) { lpNamedPropTag->aulPropTag[0] = CHANGE_PROP_TYPE(lpNamedPropTag->aulPropTag[0], PT_LONG); //Get the value of the property. hRes = lpMessage->GetProps(lpNamedPropTag, 0, &ulVal, &lpPropVal); if (lpPropVal && 1 == ulVal && PT_LONG == PROP_TYPE(lpPropVal->ulPropTag) && lpPropVal->Value.ul) { bRet = true; } } MAPIFreeBuffer(lpPropVal); MAPIFreeBuffer(lpNamedPropTag); return bRet; }
It has come to my attention that the site I was using to store my code samples, http://stephen_griffin.members.winisp.net poses a problem for some users due to the underscore. Apparently some proxy server have problems handling sites with underscores. Sounds like a bug in the proxy server to me, but still I want people to be able to get to the samples.
So I've moved them all over to http://stephengriffin.members.winisp.net. Note that I've just dropped the underscore from the name. I should have all my articles updated with the new url before the day is over.
There have been questions lately on the MAPI mailing list about how to get the connection state API working. Particularly the HrOpenOfflineObj and Advise calls. Since I had a partial sample already sitting here I figured I whip it into shape and publish it.
I'll refer most questions of implementation to the sample code itself. One thing does need to be called out though: This API only works in process. The only intended clients of this API are MAPI providers, COM Add-Ins, and Exchange Client Extensions. If your code is not running inside Outlook.exe, expect HrOpenOfflineObj to return MAPI_E_NOT_FOUND. This point is not made clear in the published documentation.
I've implemented this sample as a Com Add-In. When loaded, an "Offline State" menu will appear. Through this menu, you can enable/disable state monitoring, check the current state, and change the current state. A lot of the output for the sample is through OutputDebugString, so run under the debugger or use a debug monitor to watch it. It also writes a log file to c:\offstate.txt.
The sample should compile in VC6 or VS 2003. I haven't tested it with VS 2005 yet, but it ought to work there as well.
Here's the download link: http://stephengriffin.members.winisp.net/OfflineStateAddIn/OfflineStateAddIn.zip
Thanks to JasonJoh for writing some of the UI that I didn't feel like writing, and thanks to Shawn Walker for providing the impetus for fixing up and publishing the sample in the first place.
[11/11/05] Fixed sample URL