How to attach item change listeners on calendars from multiple exchange accounts

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

How to attach item change listeners on calendars from multiple exchange accounts
 
Horatiu Muresan


Guest


Hello,

I'm having a problem with the ItemChanged/ItemMoved event listeners on calendars when multiple Microsoft Exchange email accounts(on different Microsoft Exchange servers) are added to the same Outlook profile(tried outlook 2016, but I think 2013 and possibly 2010 have the same problem). On the calendars tab I see a blue and a green calendar, blue for one of the Microsoft Exchange accounts, green for the other. The ItemChange/ItemMove events are triggered on the blue one, not triggered at all on the green one.
I'm attaching the listener to the calendar like this:

calendarFolderListener.ConnectTo(ADXOlDefaultFolders.olFolderCalendar, true, true);

,where calendarFolderListener is an OutlookItemsEventsClass instance.

Do you have any suggestions on how to attach the listener also to the green calendar?

See picture here:

[img]https://scontent-frt3-1.xx.fbcdn.net/v/t31.0-8/15676108_1327647813943027_1797665894833414793_o.jpg?oh=7194c42d8017f1ce0bfe04aea7755ce3&oe=58DAC580[/img]

Thank you!

Regards from Romania(GMT+2),
Horatiu
Posted 22 Dec, 2016 10:41:22 Top
Andrei Smolin


Add-in Express team


Posts: 18829
Joined: 2006-05-11
Hello Horatiu,

Horatiu Muresan writes:
calendarFolderListener.ConnectTo(ADXOlDefaultFolders.olFolderCalendar, true, true);


This line only connects to the default calendar of your default store.

In the Outlook UI, press Alt+F11 to open the VBA IDE. In the VBA IDE, in the Project Explorer, insert a module, double click the newly-added module and paste the following macro in the code pane:

Sub GetCalendars()
Dim OutlookApp As Outlook.Application
Set OutlookApp = Application
Dim cm As Outlook.CalendarModule
Set cm = OutlookApp.ActiveExplorer.NavigationPane.CurrentModule
Dim iGroup As Integer
Dim iFolder As Integer
Dim outlookFolder As Outlook.Folder
Dim navFolder As Outlook.NavigationFolder
Dim str As String
For iGroup = 1 To cm.NavigationGroups.Count
    Debug.Print "Navigation Group=" + cm.NavigationGroups.Item(iGroup).Name
    For iFolder = 1 To cm.NavigationGroups.Item(iGroup).NavigationFolders.Count
        Set navFolder = cm.NavigationGroups.Item(iGroup).NavigationFolders.Item(iFolder)
        Debug.Print "  Navigation Folder=" + navFolder.DisplayName, "IsSelected=" + CStr(navFolder.IsSelected)
        If navFolder.IsSelected Then
            On Error Resume Next
            Set outlookFolder = navFolder.Folder
            On Error GoTo 0
            If outlookFolder Is Nothing Then
                Debug.Print "    Can't get the Outlook.Folder object"
            Else
                str = ""
                On Error Resume Next
                str = outlookFolder.FolderPath
                On Error GoTo 0
                If str = "" Then
                    Debug.Print "    Folder.FolderPath is unknown"
                Else
                    Debug.Print "    Folder.FolderPath=" + str
                End If
                Set outlookFolder = Nothing
            End If
        End If
    Next iFolder
Next iGroup
End Sub


In the Outlook UI, use the controls at the bottom of the Navigation Pane to switch to the Calendar module; the macro above doesn't check this and it will just break if a different module is opened. Switch back to the VBA IDE, place the text cursor on any line of the macro and press F5. Now press Ctrl+G to open the Immediate window and study the output.

You may need to know the following details about VBA macros:
- unlike a .NET based code, VBA releases *all* the COM objects that your code creates
- On Error Resume Next supplied with On Error Goto 0 stands for a try/catch block with the catch block empty

Hope this helps.


Andrei Smolin
Add-in Express Team Leader
Posted 23 Dec, 2016 08:12:18 Top
Horatiu Muresan


Guest


Thank you Andrei, it was a big help!

I did it like this in the end, seems to work fine so far (please let me know if you see anything not right):


1. Attach listeners to all calendars:


        public List<OutlookItemsEventsClass> calendarFolderListeners;        

        private void NavigateFolders(string deleteFolderEntryId)
        {
            Outlook.NameSpace session = null;
            Outlook.Folders folders = null;
            try
            {
                session = OutlookApp.Session;
                folders = session.Folders;
                for (int i = 1; i <= folders.Count; i++)
                {
                    Outlook.MAPIFolder folder = null;
                    try
                    {
                        folder = folders[i];
                        NavigateSubFoldersRecursively(folder,deleteFolderEntryId);
                    }
                    catch
                    {

                    }
                    finally
                    {
                        Release(folder);
                    }
                }
            }
            catch
            {

            }
            finally
            {
                Release(folders);
                Release(session);
            }
        }

        private void NavigateSubFoldersRecursively(Outlook.MAPIFolder folder, string deleteFolderEntryId)
        {
            Outlook.Folders folders = null;
            try
            {
                folders = folder.Folders;
                if (folders == null || folders.Count == 0)
                    return;

                for (int i = 1; i <= folders.Count; i++)
                {
                    var fld = folders[i];
                    if (fld.DefaultItemType == Microsoft.Office.Interop.Outlook.OlItemType.olAppointmentItem)
                    {
                        var listener = new OutlookItemsEventsClass(this, deleteFolderEntryId, fld.FullFolderPath);
                        listener.ConnectTo(fld, true, true);
                        calendarFolderListeners.Add(listener);
                    }
                    NavigateSubFoldersRecursively(fld, deleteFolderEntryId);
                    Release(fld);
                }
            }
            catch
            {

            }
            finally
            {
                Release(folders);
            }
        }



2. Find the correct listener for a given appointment whenever needed ( on inspector activate, item move etc):


        private OutlookItemsEventsClass GetListener(Outlook.AppointmentItem appt)
        {
            Outlook.MAPIFolder folder = null;
            try
            {
                folder = appt.Parent;
                foreach(var listener in calendarFolderListeners)
                {
                    if (listener.FullCalendarPath == folder.FullFolderPath)
                        return listener;
                }
            }
            catch
            {

            }
            finally
            {
                Release(folder);
            }
            return null;
        }



3. Disconnect all listeners at shut down:


        private void AddinModule_AddinBeginShutdown(object sender, EventArgs e)
        {
            foreach (var listener in calendarFolderListeners)
            {
                listener.RemoveConnection();
            }
        }
Posted 27 Dec, 2016 06:27:54 Top
Andrei Smolin


Add-in Express team


Posts: 18829
Joined: 2006-05-11
Hello Horatiu,

I would use MAPIFolder.EntryId instead of MAPIFolder.FolderPath to identify a listener: I believe the latter may fire an exception in some cases.


Andrei Smolin
Add-in Express Team Leader
Posted 27 Dec, 2016 07:12:44 Top
Horatiu Muresan


Guest


You are right, thank you!

Changed to use EntryID instead of the unreliable folder path.

Regards from Romania (GMT+2),
Horatiu Muresan
Posted 27 Dec, 2016 07:29:32 Top
Horatiu Muresan


Guest


Happy Holidays! All the best in the upcoming year!
Posted 27 Dec, 2016 07:49:10 Top
Andrei Smolin


Add-in Express team


Posts: 18829
Joined: 2006-05-11
Happy New Year!


Andrei Smolin
Add-in Express Team Leader
Posted 27 Dec, 2016 07:55:49 Top