I don’t normally write much about the Outlook Object Model, but this was just too interesting to pass up. Suppose we run the following code in Outlook 2003 VBA:
Sub TestHRESULT() Dim ons As Outlook.NameSpace ' If running this code in Outlook 2007 VBA, use Outlook.Folder here Dim f As Outlook.MAPIFolder Dim imi As Outlook.MailItem Set ons = Me.Application.GetNamespace("MAPI") Set f = ons.GetDefaultFolder(olFolderInbox) Set imi = f.Items.GetFirst On Error Resume Next imi.SaveAs "c:?", Outlook.OlSaveAsType.olMSG Debug.Print "Error: " & Hex(Err.Number) End Sub
What would we expect to happen? The path we passed to SaveAs is invalid, so we should get an error. Let’s see what it prints the first few times we run it:
Error: A72300FC Error: A93300FC Error: AB4300FC
What gives? Some of the digits here are constant (like the 00FC at the end) but why is the beginning changing? Turns out this is a bug in the way the Outlook Object Model is handling error codes. Under the covers, Outlook has gotten the right error code. But while passing this error around internally, the designers of Outlook wanted a simple way to track when and where the error happened. They did this by hijacking 11 unused bits of the HRESULT – specifically bits 20-30 (AKA – 0x7FF00000). What’s supposed to happen is that these bits get stripped out before they get returned to the caller. However, we missed a few cases and these extra bits sometimes get out.
However, since we know what extra bits got set, we can clear them and get the real error code. Here’s how we can do this in VBA:
Debug.Print "Error: " & Hex(Err.Number And Not &H7FF00000)
Which will produce the desired result:
Looking this error code up, we find it is STG_E_INVALIDNAME, an appropriate error for an invalid file path.
BTW – we’re pretty sure we’ve squashed this bug in Outlook 2007