0
votes

I am trying to get the information from an email that I previously opened (by doubleclicking) in outlook. The code works fine until I open multiple emails. What I am finding is that when I click on an email, the inspector activates, but I am getting the information from the last active window, not the current one that I clicked on.

Here is my code:

using Outlook = Microsoft.Office.Interop.Outlook;
using System.Diagnostics;
using System.Threading;

namespace OutlookWindowActivateTest
{
    public partial class ThisAddIn
    {
        //Outlook.Inspectors OurInspectors;
        Outlook.Inspector ActiveInspector;
        Outlook.MailItem ActiveMailItem;

        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
            Debug.WriteLine("LOADING CODE");
            Application.Inspectors.NewInspector += new Outlook.InspectorsEvents_NewInspectorEventHandler(Mail_Debugger);
        }

        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
            // Note: Outlook no longer raises this event. If you have code that 
            //    must run when Outlook shuts down, see https://go.microsoft.com/fwlink/?LinkId=506785
        }

        public void Mail_Debugger(Outlook.Inspector Inspector)
        {
            Debug.WriteLine("###START DEBUGS VOID MAIL INSPECTOR###");
            // This will fire when an email item is opened in its own window WILL NOT FIRE if you just preview
            if (Inspector.CurrentItem is Outlook.MailItem)
            {
                // this part is correct when I doubleclick an email to open it
                Outlook.MailItem OpenedMailItem = Inspector.CurrentItem as Outlook.MailItem;
                Debug.WriteLine($"  Email doubleclicked -> MailItem details:");
                Debug.WriteLine($"      Subject: {OpenedMailItem.Subject}");
                Debug.WriteLine($"      To: {OpenedMailItem.To}");
                Debug.WriteLine($"      From name: {OpenedMailItem.Sender.Name}");
                Debug.WriteLine($"      From email: {OpenedMailItem.Sender.Address}");
                Debug.WriteLine($"      Conversation ID: {OpenedMailItem.ConversationID}");
                Debug.WriteLine($"  Opened email is {OpenedMailItem.Subject}");
                ((Outlook.InspectorEvents_Event)Inspector).Activate += new Outlook.InspectorEvents_ActivateEventHandler(InspectorActivate);
                ((Outlook.InspectorEvents_Event)Inspector).Deactivate += new Outlook.InspectorEvents_DeactivateEventHandler(InspectorDeactivate);
                ((Outlook.InspectorEvents_Event)Inspector).Close += new Outlook.InspectorEvents_CloseEventHandler(InspectorClose);
                Inspector.PageChange += new Outlook.InspectorEvents_10_PageChangeEventHandler(InspectorPageChange);
            }
            Debug.WriteLine($"  Number of inspectors is {Application.Inspectors.Count}");
            Debug.WriteLine("       Inspector info:");
            foreach (Outlook.Inspector insp in Application.Inspectors)
            {
                Debug.WriteLine($"      Inspector is {insp.Caption}");
            }
            Debug.WriteLine("###END DEBUGS VOID MAIL INSPECTOR###");
        }

        private void InspectorPageChange(ref string page)
        {
            // this also happens when you doubleclick an email in outlook to open it
            Debug.WriteLine("Inspector page has changed");
            Debug.WriteLine($"      {page}");

        }
        private void InspectorClose()
        {
            Debug.WriteLine("Inspector has closed");
        }

        private void InspectorActivate()
        {
            Debug.WriteLine("Inspector was activated by someone clicking on an outlook window that is NOT the base window");
            ActiveInspector = Application.ActiveInspector();
            if (ActiveInspector is null)
            {
                Debug.WriteLine("The inspector is null because it is not ready....");
            }
            else
            {
                Debug.WriteLine($"Caption is {ActiveInspector.Caption}");
                object selectedItem = ActiveInspector.CurrentItem;
                if (selectedItem != null)
                {
                    if (selectedItem is Outlook.MailItem)
                    {
                        ActiveMailItem = selectedItem as Outlook.MailItem;
                        Debug.WriteLine($"ACTIVE INSPECTOR -> MailItem details:");
                        Debug.WriteLine($"      Subject: {ActiveMailItem.Subject}");
                        Debug.WriteLine($"      To: {ActiveMailItem.To}");
                        Debug.WriteLine($"      From name: {ActiveMailItem.Sender.Name}");
                        Debug.WriteLine($"      From email: {ActiveMailItem.Sender.Address}");
                        Debug.WriteLine($"      Conversation ID: {ActiveMailItem.ConversationID}");
                    }
                }
            }
                
        }

        private void InspectorDeactivate()
        {

            Debug.WriteLine("Inspector was deactivated");
            //if (ActiveMailItem != null)
            //{
            //    Debug.WriteLine($"  INSPECTOR -> OLD MailItem details:");
            //    Debug.WriteLine($"      Subject: {ActiveMailItem.Subject}");
            //    Debug.WriteLine($"      To: {ActiveMailItem.To}");
            //    Debug.WriteLine($"      From name: {ActiveMailItem.Sender.Name}");
            //    Debug.WriteLine($"      From email: {ActiveMailItem.Sender.Address}");
            //    Debug.WriteLine($"      Conversation ID: {ActiveMailItem.ConversationID}");
            //    Debug.WriteLine($"");
            //}
        }


        #region VSTO generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisAddIn_Startup);
            this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
        }

        #endregion
    }
}

I have spent a long time researching this, but clearly I am missing something. I feel that I need to wait for the active inspector / current item to change before attempting to get the Active Inspector. I had a look online and found a few links inclusing this:

https://social.msdn.microsoft.com/Forums/en-US/a17733ec-4420-4c7a-aa6a-23a9c9ee68e1/how-to-get-the-mail-item-opened-window?forum=outlookdev

But this like the others is not quite what I'm looking for because I am not dealing with a new inspector. I'm dealing with one already opened and simply working between 2 or more open inspectors.

The function "Mail_Debugger" seems to work fine - when I doubleclick an email in outlook, when it opens, I get the information for the correct email that I just opened.

In closing, my goal is to be able to open multiple emails by doubleclicking in outlook to open then in their own window and then click those email windows to get the active inspector which should be able to provide information about the email in the window.

Any idea what I am doing wrong? Thankyou

2
What exactly initiates that code? Is that a ribbon button click event? Or some other event? - Dmitry Streblechenko
Its a VSTO that runs when outlook runs. By capturing events for the new inspectors, I should be able to grab info for every new email opened. From here, I am trying to get the details from those open emails. i.e conversationID, sender, subject, etc - IamSierraCharlie
So it is the NewInspector event? But the Inspector object is passed as a parameter to your event handler. And it is might be different from Application.ActiveExpector since the new inspector might not be visible just yet. - Dmitry Streblechenko
Sorry for my delay, yes its a new inspector. As I understand it, each time you open a new email (i.e. double click on an email from the inbox), a new inspector is created. I think you are right. The inspector seems to be there, but not visible. What I've found is that running the call in a thread seems to work - as per the code below, I'm doing a while inspector is null, it loops once before the inspector becomes availeble. This is the only way I've managed to make it work. Is this a good practice or is there another way? - IamSierraCharlie

2 Answers

0
votes

Your NewInspectorCreated event will never fire - you are setting up the event handler on an implicit variable created by the compiler - as soon as GC releases it, the event will no longer fire. You must keep the variable raising events alive.

    public partial class ThisAddIn
    {
        //Outlook.Inspectors OurInspectors;
        Outlook.Inspector ActiveInspector;
        Outlook.MailItem ActiveMailItem;
        Outlook.Inspectors _inspectors;

        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
            Debug.WriteLine("LOADING CODE");
            _inspectors = Application.Inspectors;
            _inspectors.NewInspector += new Outlook.InspectorsEvents_NewInspectorEventHandler(Mail_Debugger);
        }
0
votes

After plenty of trial and error here, I think I've finally worked this out. The point above was a big consideration in coming up with another way - the activeinspector is not visible so you cannot simply call for it because it will always be null if you have previously released the item or it will be equal to the last found activeinspector. Here is how I got around the issue - my code is not perfect, but it certainly works as expected without calling another thread. Additionally from my reading, its a good idea not to have strong references to your delegates (Not my issue here, but still good practice) My way forward involved getting the active window instead of the active inspector and casting it as an inspector.

using Outlook = Microsoft.Office.Interop.Outlook;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;

namespace OutlookWindowActivateTest
{
    public partial class ThisAddIn
    {
        Outlook.Inspectors MyInspectors;
        Outlook.Inspector activeInspector;
        Outlook.MailItem ActiveMailItem;
        Outlook.InspectorsEvents_NewInspectorEventHandler InspectorEventHandler;
        Outlook.InspectorEvents_ActivateEventHandler inspectorEvents_Activate;
        Outlook.InspectorEvents_DeactivateEventHandler inspectorEvents_Deactivate;
        Outlook.InspectorEvents_CloseEventHandler inspectorEvents_Close;

        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
            Debug.WriteLine("LOADING CODE");
            InspectorEventHandler = new Outlook.InspectorsEvents_NewInspectorEventHandler(NewInspectorCreated);
            inspectorEvents_Activate = new Outlook.InspectorEvents_ActivateEventHandler(InspectorActivate);
            inspectorEvents_Deactivate = new Outlook.InspectorEvents_DeactivateEventHandler(InspectorDeactivate);
            inspectorEvents_Close = new Outlook.InspectorEvents_CloseEventHandler(InspectorClose);
            MyInspectors = Application.Inspectors;
            MyInspectors.NewInspector += InspectorEventHandler;
        }

        public void NewInspectorCreated(Outlook.Inspector Inspector)
        {
            activeInspector = Inspector;
            Debug.WriteLine("###START DEBUGS VOID MAIL INSPECTOR###");
            // This will fire when an email item is opened in its own window WILL NOT FIRE if you just preview
            if (activeInspector.CurrentItem is Outlook.MailItem)
            {
                // this part is correct when I doubleclick an email to open it
                Outlook.MailItem OpenedMailItem = activeInspector.CurrentItem as Outlook.MailItem;
                Debug.WriteLine($"  Email doubleclicked -> MailItem details:");
                Debug.WriteLine($"      Subject: {OpenedMailItem.Subject}");
                Debug.WriteLine($"      To: {OpenedMailItem.To}");
                Debug.WriteLine($"      From name: {OpenedMailItem.Sender.Name}");
                Debug.WriteLine($"      From email: {OpenedMailItem.Sender.Address}");
                Debug.WriteLine($"      Conversation ID: {OpenedMailItem.ConversationID}");
                Debug.WriteLine($"  Opened email is {OpenedMailItem.Subject}");
                // add these events to capture when an opened email window is clicked on , closed or clicked away from
                ((Outlook.InspectorEvents_Event)activeInspector).Activate += inspectorEvents_Activate;
                ((Outlook.InspectorEvents_Event)activeInspector).Deactivate += inspectorEvents_Deactivate;
                ((Outlook.InspectorEvents_Event)activeInspector).Close += inspectorEvents_Close;
            }
            Debug.WriteLine($"  Number of inspectors is {Application.Inspectors.Count}");
            Debug.WriteLine("       Inspector info:");
            foreach (Outlook.Inspector insp in Application.Inspectors)
            {
                Debug.WriteLine($"      Inspector is {insp.Caption}");
            }
            Debug.WriteLine("###END DEBUGS VOID MAIL INSPECTOR###");
        }
        private void InspectorClose()
        {
            Debug.WriteLine("Inspector has closed");
            // work to do here
        }
        private void InspectorActivate()
        {
            Debug.WriteLine("Inspector was activated by someone clicking on an outlook window that is NOT the base window");
            var ThisWindow = Application.ActiveWindow();
            if (ThisWindow is Outlook.Inspector)
            {
                Debug.WriteLine("This window is an inspector");
                activeInspector = ThisWindow as Outlook.Inspector;
                activeInspector.Activate();
                if (activeInspector.CurrentItem is Outlook.MailItem)
                {
                    ActiveMailItem = activeInspector.CurrentItem;
                    Debug.WriteLine("The active inspector is a mail item");
                    Debug.WriteLine($"ACTIVE INSPECTOR -> MailItem details:");
                    Debug.WriteLine($"      Subject: {ActiveMailItem.Subject}");
                    Debug.WriteLine($"      To: {ActiveMailItem.To}");
                    Debug.WriteLine($"      From name: {ActiveMailItem.Sender.Name}");
                    Debug.WriteLine($"      From email: {ActiveMailItem.Sender.Address}");
                    Debug.WriteLine($"      Conversation ID: {ActiveMailItem.ConversationID}");
                }
            }
            else
            {
                Debug.WriteLine("It is something else"); // I end up here when I open an email in a new window the first time (i.e. double click it)

            }
        }
       
        private void InspectorDeactivate()
        {
            Debug.WriteLine("This Inspector is being deactivated");
            // more work to do here
        }

        #region VSTO generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InternalStartup()
        {
            this.Startup += new System.EventHandler(ThisAddIn_Startup);
            this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
        }
        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
            // Note: Outlook no longer raises this event. If you have code that 
            //    must run when Outlook shuts down, see https://go.microsoft.com/fwlink/?LinkId=506785
        }

        #endregion
    }
}

With this code, when I double click to open the email the first time, I dont get the active window, but I can handle that elsewhere so its not an issue for me. What this code does do for me is allow me to click on the email opened in its own window and get that window as the inspector. From here, I can find any information is the email in question that is needed.