Search code examples
c#outlookvstomailitem

Outlook VSTO - Adding file path/hyperlink to MailItem WordEditor from Outlook VSTO


I am having following problem. I have a window that opens and allows me to select some files. Then I can right-click on that window and choose to attach paths of selected files to a new mail dialog.

The workflow is like this:

  1. I open my windows and select couple of files

  2. Right-click, choose to add selected files paths to MailItem

  3. Logic will check if there is an ActiveInspector

    3.1. If there is one, I get its CurrentItem as MailItem (so, new mail dialog exists and does not need to be created)

    3.2. If there is none, I call CreateItem(Microsoft.Office.Interop.OLItemType.olMailItem) to create new mail dialog and then I call MailItem.Display(false) to display the mail item dialog

  4. Next I loop through list of selected files paths and add them to the new mail dialog. This works great.

PROBLEM If I open my window for the 2nd time to select more files and add their paths to the same mail dialog I opened earlier, they are not added.

Here is the code:

public void AddFilePaths(List<string> paths)
{
    if (paths.Count > 0)
    {
        var inspector = MyAddIn.Application.ActiveInspector();
        MailItem mi = null;
        bool newMailItem = false;

        if (inspector != null)
        {
            // If new mail dialog is already open, just get it.
            // This is called on my 2nd attempt to add paths to new mail.
            // This MailItem is the same one created on 1st call in below
            // else block.  I confirmed that by adding some dummy email
            // Body in below else block, then checking for it here on 
            // 2nd call.  I think this proves that correct 
            // Inspector/MailItem is returned here.
            mi = MyAddIn.Application.ActiveInspector().CurrentItem as MailItem;
        }
        else
        {
            // create new mail dialog and display it
            // this is called on my 1st call to add paths to new mail
            mi = MyAddIn.Application.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem);
            mi.Body = "Dummy email body"; 
            newMailItem = true;
        }

        if (newMailItem)
        {
            mi.Display();
            inspector = MyAddIn.Application.ActiveInspector();
        }

        if (inspector != null)
        {
            foreach (var path in paths)
            {
                AddPathToActiveInspector(path);
            }
        }
    }
}

The code above calls this method to add path to the current ActiveInspector WordEditor:

public void AddPathToActiveInspector(string path)
{
    var inspector = MyAddIn.Application.ActiveInspector();
    dynamic we = inspector.WordEditor;
    dynamic word = we.Application;
    const string nl = "\n";

    // I have noticed that if I am debugging, this line will throw error
    // "COMException was unhandled by user code", "An exception of type
    // System.Runtime.Interop.Services.COMException occurred in 
    // System.Dynamic.dll but was not handled by user code:
    // Message: This command is not available
    // InnerException: null
    // I have also seen following error on 2nd attempt: "The TypeText    
    // method or property is not available because the document is
    // locked for editing."
    word.Selection.TypeText(nl);

    string address = path;
    string subAddress = "";
    string screenTip = "";
    string displayText = path; 
    word.ActiveDocument.Hyperlinks.Add(word.Selection.Range, ref address, ref subAddress, ref screenTip, ref displayText);
    word.Selection.TypeText(" "); 
}

Solution

  • I would simply create a new email message each time you are adding your paths to avoid the possibility of adding paths to a wrong email message which could happen if you have opened multiple emails.

    1. Add a reference to Microsoft.Office.Interop.Word to your project
    2. Add using Microsoft.Office.Interop.Word on top of your class file

    Here is the code:

    public void AddFilePaths(List<string> paths)
    {
        if (paths.Count > 0)
        {
            MailItem  mi = ThisAddIn.Application.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem);
            mi.Display();
            if (mi!= null)
            {
                foreach (var path in paths)
                {
                    AddPathsToNewEmailMessage(path);
                }
            }
        }
    }
    

    The code above calls this method to add the path to the new email message WordEditor:

    public void AddPathsToNewEmailMessage(string path)
    {
        object link = url;
        object result = "url";
        object missing = Type.Missing;
        string nl = "\n";
    
        var inspector = ThisAddIn.Application.ActiveInspector();
        MailItem currMessage = inspector.CurrentItem;
        Word.Document doc = currMessage.GetInspector.WordEditor;
        Word.Selection sel = doc.Windows[1].Selection;
        doc.Hyperlinks.Add(sel.Range, ref result, ref missing, ref missing, ref link, ref missing);
        sel.EndKey(Word.WdUnits.wdLine);
        sel.InsertAfter(nl);
        sel.MoveDown(Word.WdUnits.wdLine);
    }