Issue with Outlook UserProperties

Add-in Express™ Support Service
That's what is more important than anything else

Issue with Outlook UserProperties
 
Antony Jones


Guest


Hello there,

We've developed a custom Outlook 2010 (note this is an upgrade form a Office 2003 add-in that has been working successfully for 3 years or so) add-in that integrates with a 3rd party Document Management Solution.

When sending emails we append a tracking reference onto the email subject and add a custom user property to the email marking the email as Filed=False.

When the item hits the sent items folder we then grab it, check for the presence of the Filed property file it into the document management system and update the Filed property to True.

New emails are also inspected for the presence of the tracking code (in the messages subject) and filed automatically as they arrive.

In most instance this works fine but occasionally we get an error when working with the UserProperties: "The function cannot be performed because the message has been changed."

It appears that the email's state (based on msg.saved being false) needs
to be saved prior to us manipulating the user properties.

It seems very random and can occur with a new email, responding to an existing email or when new emails arrive.


Does anyone have and thoughts?
Posted 08 Mar, 2011 13:32:52 Top
Eugene Astafiev


Guest


Hi Antony,

Did you try to debug? Do you save the message after you did any changes?

Also please make sure that you release underlying COM objects properly. You can read more about this in the http://www.add-in-express.com/creating-addins-blog/2008/10/30/releasing-office-objects-net/ article on our technical blog. Does it help?
Posted 09 Mar, 2011 05:47:29 Top
Antony Jones


Guest


Hello,

the issue only appears when deployed to our clients live site we've not been able to replicate it in dev on our own servers. Even then it seems very random.

The problem seems to be that the message is already in a state that needs to be saved before we start to manipulate it. We have tried saving the messages before we start to maniplaute the user properties properties but unfortuantely it makes little difference.

Can post some code if it helps?

Tony
Posted 09 Mar, 2011 11:40:24 Top
Eugene Astafiev


Guest


Hi Antony,

May I see your code?
Posted 10 Mar, 2011 03:46:34 Top
Heinz-Josef Bomanns




Posts: 206
Joined: 2008-02-28
Hi Antony,

i had a similar problem with one of our add ins that uses UserProperties and found the reason in this techinfo from Microsoft http://support.microsoft.com/kb/907985/en-us - maybe it's of help for you...
__________________
Greetings, HJB
Posted 10 Mar, 2011 20:52:57 Top
Eugene Astafiev


Guest


Hi guys,

Antony, is the issue still alive?

Thank you for sharing your knowledge, Heinz-Josef!
Posted 11 Mar, 2011 06:00:23 Top
Antony Jones


Guest


Hello,

Sorry for the delay (holiday which is now alas over). Heinz-Josef many thanks for the link it has though not helped in this instance.

Function that amends the User Property is below.

As I mentioned when the message enter the function myMsg.Saved is True

When I add / update the reference myMsg.Saved is False so I try so I call the save method. It's then I get the "System.Runtime.InteropServices.COMException (0x80040109): The function cannot be performed because the message has been changed." message.


Any thoughts / advice appriciated, the users rely on these UserProperties to determine what has been filed to Document Management system or not.

Many thanks,
Tony

Private Function UpdateEmailWithRef(ByVal Filed As TriState, ByVal myMsg As Outlook.MailItem, ByVal EmailSubject As String, Optional ByVal ToBeFiled As Boolean = False) As Boolean

LogEntry("UpdateEmailWithRef", "Started")

Dim EntryID As String = myMsg.EntryID

Try

If myMsg.Subject <> EmailSubject Then ' subject requires updating
myMsg.Subject = EmailSubject
End If

If Filed = TriState.True Or Filed = TriState.False Then

If IsNothing(myMsg.UserProperties.Find("FiledToLaserFiche")) Then

' add new property / value
myMsg.UserProperties.Add("FiledToLaserFiche", Outlook.OlUserPropertyType.olText)
myMsg.UserProperties.Find("FiledToLaserFiche").Value = Filed.ToString
LogEntry("UpdateEmailWithRef", "User Property Added")

Else

If myMsg.UserProperties.Find("FiledToLaserFiche").Value <> Filed.ToString Then
' value exists / is different needs to be updated
myMsg.UserProperties.Find("FiledToLaserFiche").Value = Filed.ToString
LogEntry("UpdateEmailWithRef", "User Property Deleted / Added")
End If

End If

End If

If Not myMsg.Saved Then
myMsg.Save()
LogEntry("UpdateEmailWithRef", "User Property Saved")
Else
LogEntry("UpdateEmailWithRef", "Nothing Changed: No Save Required")
End If

Return True

Catch ex As Exception

LogEntry("UpdateEmailWithRef", ex.ToString)
Return False

Finally
LogEntry("UpdateEmailWithRef", "Finished")
End Try

End Function
Posted 21 Mar, 2011 07:15:23 Top
Dmitry Kostochko


Add-in Express team


Posts: 2875
Joined: 2004-04-05
Hi Antony,

Thank you for the code.

Aside from non-released COM interfaces, your code looks correct. I would suggest that you do release all COM interfaces, even such small ones as UserProperties and UserProperty. Also, I have one question: from what event handler do you call the UpdateEmailWithRef method?
Posted 21 Mar, 2011 10:37:12 Top
Antony Jones


Guest


Hi Dimitry,

Many thanks for your speedy response.

The routine is called in serveral places typically it will be one of the following:

When a Email is added to the SentItemsFolder via an Event Sink
When the user selects a mail message (or messages) to File Manually (ribbon click event from eith the main Outlook ribbon or a emails ribbon)
When a Email arrives via adxOutlookEvents_NewMailEx

Prior to calling the rountine I do save the message to local disk (so it can be filed to the repository).

I typically relese the COM objects with this code :

If (myMSG IsNot Nothing) Then Marshal.ReleaseComObject(myMSG)

Once the routine has been called (example):

Dim Filed As Boolean = FileEmail(myEmail, myMSG, , , False)
UpdateEmailWithRef(Filed, myMSG, myEmail.Subject)
If (myMSG IsNot Nothing) Then Marshal.ReleaseComObject(myMSG)

Many thanks,
Antony
Posted 21 Mar, 2011 10:57:11 Top
Dmitry Kostochko


Add-in Express team


Posts: 2875
Joined: 2004-04-05
Hi Antony,

Thank you for the details.

I am afraid I do not know the exact reason why the error occurs. Do your customers have other COM add-ins installed? Do you execute your code in the main add-in thread?

As to the non-released COM interfaces, I meant the code of the UpdateEmailWithRef method. Please note, you are using code constructions like myMsg.UserProperties.Find("FiledToLaserFiche").Value. There are two COM objects here that need to be released in one code line, the UserProperties property and the Find method return COM interfaces. I would suggest using some code similar to this:

            If Filed = TriState.True Or Filed = TriState.False Then

                Dim props As Outlook.UserProperties = myMsg.UserProperties
                If props IsNot Nothing Then
                    Try

                        Dim prop As Outlook.UserProperty = props.Find("FiledToLaserFiche")

                        If IsNothing(prop) Then

                            ' add new property / value 
                            prop = props.Add("FiledToLaserFiche", Outlook.OlUserPropertyType.olText)
                            prop.Value = Filed.ToString
                            LogEntry("UpdateEmailWithRef", "User Property Added")

                        Else

                            If prop.Value <> Filed.ToString Then
                                ' value exists / is different needs to be updated 
                                prop.Value = Filed.ToString
                                LogEntry("UpdateEmailWithRef", "User Property Deleted / Added")
                            End If

                        End If

                        If prop IsNot Nothing Then
                            Marshal.ReleaseComObject(prop)
                        End If

                    Finally
                        Marshal.ReleaseComObject(props)
                    End Try
                End If

            End If
Posted 21 Mar, 2011 13:40:33 Top