Catching Send Button in Inspector

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

Catching Send Button in Inspector
How to catch the user clicking the Send button in an Outlook Inspector 
Pino Carafa




Posts: 81
Joined: 2016-09-28
Hello Andrei,

Ok this is just getting weird. Just out of curiosity I made some modifications to the test add-in. Instead of SETTING the Property in the PropertyAccessor in the Button1_Click event handler and then trying to RETRIEVE it in the _ItemSend, I tried retrieving it immediately after setting it. Now you'd expect that to be "stupidly" trivial and it should work as a matter of course, now, or at least I would:


        Dim oPA As Outlook.PropertyAccessor = Nothing

        Try
            oPA = oItem.PropertyAccessor
        Catch

        End Try

        If Not oPA Is Nothing Then
            Try
                oPA.SetProperty("http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/CaseReference}", oItem.Subject)
            Catch ex As Exception
                System.Diagnostics.Debug.WriteLine("Error setting Case Reference: " + ex.Message)
            End Try

            'Uncommenting this makes no difference
            Try
                Marshal.ReleaseComObject(oPA)
            Catch

            End Try
            oPA = Nothing
        End If

        Try
            oPA = oItem.PropertyAccessor
        Catch

        End Try

        If Not oPA Is Nothing Then
            Try
                'Just to prove that IN HERE and AT THIS POINT the property is still normally accessible
                MsgBox(oPA.GetProperty("http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/CaseReference}"))
            Catch ex As Exception
                System.Diagnostics.Debug.WriteLine("Error Getting Case Reference in Button1_Click: " + ex.Message)
            End Try

            Try
                Marshal.ReleaseComObject(oPA)
            Catch

            End Try
            oPA = Nothing
        End If


and......
"Exception thrown: 'System.Runtime.InteropServices.COMException' in MyAddin136.dll
Error Getting Case Reference in Button1_Click: The property "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/CaseReference}" is unknown or cannot be found.
"

What is going on.....????
Posted 17 Oct, 2019 02:47:49 Top
Pino Carafa




Posts: 81
Joined: 2016-09-28
by the way - once again this is using a Profile with "Cached Exchange Mode" switched OFF and connected to an online Exchange (Outlook 365)
Posted 17 Oct, 2019 02:53:51 Top
Pino Carafa




Posts: 81
Joined: 2016-09-28
MORE craziness in NON-Cached Exchange Mode..... Start composing an email and hit Button1 ... and the error happens as stated in the previous comment.

Leave the message open. Don't send it. Walk away and make yourself a cup of coffee. Come back.

Hit Button1 again.

No error this time. The messagebox shows. And once the messagebox shows you can keep changing the message subject and you can keep hitting Button1. The messagebox will show every time.

I've timed this. In NON-cached exchange mode:
When you start composing the message and hit Button1 the error happens.
If you click Button1 again after 1 minute the error happens.
If you click Button1 again after 2 minutes the error happens.
If you click Button1 again after 3 minutes, no error. The messagebox shows.

If there was a 5, even 10 second "delay" in Non-cached exchange mode before Retrieving the Property succeeds, I could build that into the Add-in, check the ConnectionMode and leave the button disabled for that interval. But I can't do that for a delay of up to 3 minutes. At this stage it's starting to look like I'm going to have to restrict functionality unless the user switches to Cached Exchange Mode. I had rather hoped I could avoid that.
Posted 17 Oct, 2019 03:03:07 Top
Andrei Smolin


Add-in Express team


Posts: 16673
Joined: 2006-05-11
Hello Pino,

Pino Carafa writes:
No error this time.


This is AutoSave! You need to save the item. Check MailItem.Saved to find whether it is saved or not.

I also suppose you'll see the very same issue if you use a PST.

Regards from Belarus (GMT+3),

Andrei Smolin
Add-in Express Team Leader
Posted 17 Oct, 2019 04:16:39 Top
Pino Carafa




Posts: 81
Joined: 2016-09-28
You're correct (of course!) - after 3 minutes the item was autosaved and the problem no longer occurs. Which leaves me with a problem.

Here is the "workflow" of our Add-in:

1) The user starts composing an email. They click on a button to select a "case" from our "case management system". They select the case and we set the CaseReference Property in the PropertyAccessor
2) The user hits Send

At this point the software enters the _ItemSend procedure and we retrieve the CaseReference Property. This fails because the Mailitem is not Saved. As you suggest, I could first Save the mailitem. Now I no longer have a problem retrieving the CaseReference.... but now I have a NEW problem.

The mailitem is now Saved in Drafts.

In our REAL add-in, when I have the CaseReference I now go and get the email recipients. Each "case" in our "Case Management System" has people stored against it as so-called "Case Associates". I go and check each Recipient and make sure that the e-mail address is stored as an e-mail address for a "Case Associate" belonging to that "Case Reference". If there is an email address that doesn't belong in there, the user gets a warning and they can choose do click "OK" at which point the e.Cancel property is set to True and the email is not sent.

...

And then the User decided "to *bleep* with this" and X-es out of the email.

Now I have an item sitting in the Drafts folder.

Repeat this behaviour 1000 times.

Now I have 1000 items sitting in the Drafts folder.

Next thing I have a customer on the phone screaming at me that they have 1000 emails in their Drafts folder and they can't find the draft they *deliberately* created 2 months ago and "why are you creating all this junk in my mail folder?"

I have no way of knowing that the user didn't do what I just outlined, and at some point cancelled and instead of X-ing out of the email made a few more changes and then *deliberately* decided to save the email as a Draft. So I can't even set a property on the email and automatically remove drafts containing that property.

So many chickens. So many eggs.

This is why I originally asked for a way of knowing the user has clicked the Send button. Because if I can do THAT, instead of storing the CaseReference in the PropertyAccessor, I can store it in properties on the ADXOlForm without setting anything in the PropertyAccessor. I can then set the properties in the PropertyAccessor ONLY when the user hits "Send" and before processing enters the _ItemSend procedure. I could check the Recipients at that point, too, and do all the checking associated with those. And in fact I would not need the _ItemSend procedure at all anymore ...

But as you said.... there is no native way of doing that. You *did*, however, mention an API solution. As dirty as that is.... I may need to seriously think of implementing that. Would you have an example of such a thing?
Posted 17 Oct, 2019 04:45:49 Top
Andrei Smolin


Add-in Express team


Posts: 16673
Joined: 2006-05-11
Pino Carafa writes:
Now I no longer have a problem retrieving the CaseReference.... but now I have a NEW problem.
The mailitem is now Saved in Drafts.


You can save mail items when in ItemSend event, after you validate the email (BTW, this can be a meeting request, remember?) and you need that property to handle it.

Pino Carafa writes:
This is why I originally asked for a way of knowing the user has clicked the Send button.


Use the fact that clicking Send ends with the ItemSend event (unless the send process is cancelled on an earlier stage). Save the required data to ADXOlForm. When in ItemSend, get MailItem.Inspector, scan ADXOlForms opened by that ADXOlFormsCollectionItem, compare the Inspector with ADXOlForm.InspectorObj to find *the* ADXOlForm and retrieve the data.

Regards from Belarus (GMT+3),

Andrei Smolin
Add-in Express Team Leader
Posted 17 Oct, 2019 09:03:38 Top
Pino Carafa




Posts: 81
Joined: 2016-09-28
Hello Andrei,

Ok I think I got it! I added a CaseReference property to the ADXOlForm and I'm setting it instead of the PropertyAccessor, and then I change the ItemSend as follows. Can you just cast your eye over this to see if I am now doing it correctly, especially with regard to marshaling - for example I am Releasing an oInspector object here and I'm getting the Inspector through e.Item.GetInspector() - just want to make sure I'm leaving nothing hanging ... ?

The good news is - when I'm testing it it appears to be working fine!


    Private Sub AdxOutlookAppEvents1_ItemSend(sender As Object, e As ADXOlItemSendEventArgs) Handles AdxOutlookAppEvents1.ItemSend

        Dim sCaseReference As String = String.Empty

        Dim oInspector As Outlook.Inspector = Nothing

        Try
            oInspector = TryCast(e.Item.GetInspector(), Outlook.Inspector)
        Catch ex As Exception

        End Try

        If Not oInspector Is Nothing Then
            Dim oADXForm As ADXOlForm1 = Nothing
            Try
                Dim nForms As Integer = Me.AdxOlFormsCollectionItem1.FormInstanceCount
                Dim nForm As Integer = 0
                While nForm < nForms
                    Try
                        oADXForm = TryCast(Me.AdxOlFormsCollectionItem1.FormInstances(nForm), ADXOlForm1)
                        If Not oADXForm Is Nothing Then
                            sCaseReference = oADXForm.CaseReference
                        End If
                    Catch ex As Exception

                    End Try
                    nForm = nForm + 1 '0-based index
                End While
            Catch

            End Try
            Try
                Marshal.ReleaseComObject(oInspector)
            Catch

            End Try
            oInspector = Nothing
        End If

        If sCaseReference = "CancelThis" Then
            e.Cancel = True
            Exit Sub
        End If

        Dim oPA As Outlook.PropertyAccessor = Nothing

        Try
            oPA = e.Item.PropertyAccessor
        Catch

        End Try

        If Not oPA Is Nothing Then
            Try
                oPA.SetProperty("http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/CaseReference}", sCaseReference)
            Catch ex As Exception
                System.Diagnostics.Debug.WriteLine("ItemSend: Error setting Case Reference: " + ex.Message)
            End Try
            Try
                Marshal.ReleaseComObject(oPA)
            Catch

            End Try
            oPA = Nothing
        End If

        Try
            e.Item.Save()
        Catch ex As Exception

        End Try

    End Sub
Posted 18 Oct, 2019 06:11:27 Top
Pino Carafa




Posts: 81
Joined: 2016-09-28
Corrected:


    Private Sub AdxOutlookAppEvents1_ItemSend(sender As Object, e As ADXOlItemSendEventArgs) Handles AdxOutlookAppEvents1.ItemSend

        Dim sCaseReference As String = String.Empty

        Dim oInspector As Outlook.Inspector = Nothing

        Try
            oInspector = TryCast(e.Item.GetInspector(), Outlook.Inspector)
        Catch ex As Exception

        End Try

        If Not oInspector Is Nothing Then
            Dim oADXForm As ADXOlForm1 = Nothing
            Try
                Dim nForms As Integer = Me.AdxOlFormsCollectionItem1.FormInstanceCount
                Dim nForm As Integer = 0
                While nForm < nForms
                    Try
                        oADXForm = TryCast(Me.AdxOlFormsCollectionItem1.FormInstances(nForm), ADXOlForm1)
                        If Not oADXForm Is Nothing Then
                            If oADXForm.InspectorObj Is oInspector Then
                                sCaseReference = oADXForm.CaseReference
                                Exit While
                            End If
                        End If
                    Catch ex As Exception

                    End Try
                    nForm = nForm + 1 '0-based index
                End While
            Catch

            End Try
            Try
                Marshal.ReleaseComObject(oInspector)
            Catch

            End Try
            oInspector = Nothing
        End If

        If sCaseReference = "CancelThis" Then
            e.Cancel = True
            Exit Sub
        End If

        Dim oPA As Outlook.PropertyAccessor = Nothing

        Try
            oPA = e.Item.PropertyAccessor
        Catch

        End Try

        If Not oPA Is Nothing Then
            Try
                oPA.SetProperty("http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/CaseReference}", sCaseReference)
            Catch ex As Exception
                System.Diagnostics.Debug.WriteLine("ItemSend: Error setting Case Reference: " + ex.Message)
            End Try
            Try
                Marshal.ReleaseComObject(oPA)
            Catch

            End Try
            oPA = Nothing
        End If

        Try
            e.Item.Save()
        Catch ex As Exception

        End Try

    End Sub
Posted 18 Oct, 2019 06:13:28 Top
Andrei Smolin


Add-in Express team


Posts: 16673
Joined: 2006-05-11
Hello Pino,

It looks correct. I would add logging to all Catch blocks to get informed when something goes wrong.

Regards from Belarus (GMT+3),

Andrei Smolin
Add-in Express Team Leader
Posted 18 Oct, 2019 06:21:14 Top
Pino Carafa




Posts: 81
Joined: 2016-09-28
Thanks Andrei.... I will do in our "real" Add-in :-)

I think at this stage, if you ever make it to Ireland I owe you a pint.
Posted 18 Oct, 2019 06:27:03 Top