Надстройка Outlook 2010 ведет себя странно при вызове почты из другого клиента office

#c#-4.0 #outlook-addin

#c #-4.0 #outlook-надстройка

Вопрос:

Мне действительно нужна помощь с этим.

Я написал дополнение, которое добавляет некоторый текст в строку темы электронного письма при отправке, оно также устанавливает то же значение в свойстве электронного письма через PropertyAccessor. Это прекрасно работает, когда электронное письмо создается через интерфейс Outlook.

Проблема, с которой я столкнулся, заключается в том, что пользователь работает с Excel и решает отправить электронную таблицу в виде вложения из пункта меню Excel 2010 -> Файл -> Сохранить и отправить -> Отправить как вложение.

Это откроет почтовый редактор Outlook 2010, как и следовало ожидать, пользователь может адресовать электронное письмо и нажать отправить как обычно, и электронное письмо будет отправлено как обычно. Проблема в том, что редактор электронной почты не закрывается после отправки, как можно было бы ожидать.

Я использую глобальные переменные.Эта надстройка.Приложение.Событие ItemSend для внесения моих изменений в электронное письмо. Я также замечаю при отладке, что это событие срабатывает пару раз при отправке. Аргумент cancel этого события всегда равен false во время выполнения.

Ответ №1:

Наконец-то найдено то, что, кажется, работает

Разработка оболочки инспектора для Outlook 2010

В случае, если ссылка оборвется, как они, вероятно, и сделают

Вот оболочка

 namespace OutlookAddIn
{
// Eventhandler used to correctly clean up resources.
// <param name="id">The unique id of the Inspector instance.</param>
internal delegate void InspectorWrapperClosedEventHandler(Guid id);

// The base class for all inspector wrappers.
internal abstract class InspectorWrapper
{
    // Event notification for the InspectorWrapper.Closed event.
    // This event is raised when an inspector has been closed.

    // The unique ID that identifies an inspector window.
    protected InspectorWrapper(Inspector inspector)
    {
        Id = Guid.NewGuid();
        Inspector = inspector;
        // Register Inspector events here
        ((InspectorEvents_10_Event) Inspector).Close  = InspectorClose;
        ((InspectorEvents_10_Event) Inspector).Activate  = Activate;
        (Inspector).Deactivate  = Deactivate;
        (Inspector).BeforeMaximize  = BeforeMaximize;
        (Inspector).BeforeMinimize  = BeforeMinimize;
        (Inspector).BeforeMove  = BeforeMove;
        (Inspector).BeforeSize  = BeforeSize;
        (Inspector).PageChange  = PageChange;

        // Initialize is called to give the derived wrappers.
        Initialize();
    }

    public Guid Id { get; private set; }

    // The Outlook Inspector instance.
    public Inspector Inspector { get; private set; }
    public event InspectorWrapperClosedEventHandler Closed;

    // .ctor
    // <param name="inspector">The Outlook Inspector instance that should be handled.</param>

    // Event handler for the Inspector Close event.
    private void InspectorClose()
    {
        // Call the Close Method - the derived classes can implement cleanup code
        // by overriding the Close method.
        Close();

        // Unregister Inspector events.
        ((InspectorEvents_10_Event) Inspector).Close -= InspectorClose;

        // Clean up resources and do a GC.Collect().
        Inspector = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();

        // Raise the Close event.
        if (Closed != null)
        {
            Closed(Id);
        }
    }

    protected virtual void Initialize()
    {}

    // Method is called when another page of the inspector has been selected.
    // <param name="ActivePageName">The active page name by reference.</param>
    protected virtual void PageChange(ref string ActivePageName)
    {}

    // Method is called before the inspector is resized.
    // <param name="Cancel">To prevent resizing, set Cancel to true.</param>
    protected virtual void BeforeSize(ref bool Cancel)
    {}

    // Method is called before the inspector is moved around.
    // <param name="Cancel">To prevent moving, set Cancel to true.</param>
    protected virtual void BeforeMove(ref bool Cancel)
    {}

    // Method is called before the inspector is minimized.
    // <param name="Cancel">To prevent minimizing, set Cancel to true.</param>
    protected virtual void BeforeMinimize(ref bool Cancel)
    {}

    // Method is called before the inspector is maximized.
    // <param name="Cancel">To prevent maximizing, set Cancel to true.</param>
    protected virtual void BeforeMaximize(ref bool Cancel)
    {}

    // Method is called when the inspector is deactivated.
    protected virtual void Deactivate()
    {}

    // Method is called when the inspector is activated.
    protected virtual void Activate()
    {}

    // Derived classes can do a cleanup by overriding this method.
    protected virtual void Close()
    {}


    // This factory method returns a specific InspectorWrapper or null if not handled.
    // <param name=”inspector”>The Outlook Inspector instance.</param>
    // Returns the specific wrapper or null.
    public static InspectorWrapper GetWrapperFor(Inspector inspector)
    {
        // Retrieve the message class by using late binding.
        string messageClass = inspector.CurrentItem.GetType().InvokeMember("MessageClass", BindingFlags.GetProperty,
                                                                           null, inspector.CurrentItem, null);

        // Depending on the message class, you can instantiate a
        // different wrapper explicitly for a given message class by
        // using a switch statement.
        switch (messageClass)
        {
            case "IPM.Contact":
                return new ContactItemWrapper(inspector);
            case "IPM.Journal":
                return new ContactItemWrapper(inspector);
            case "IPM.Note":
                return new MailItemWrapper(inspector);
            case "IPM.Post":
                return new PostItemWrapper(inspector);
            case "IPM.Task":
                return new TaskItemWrapper(inspector);
        }

        // Or, check if the message class begins with a specific fragment.
        if (messageClass.StartsWith("IPM.Contact.X4U"))
        {
            return new X4UContactItemWrapper(inspector);
        }

        // Or, check the interface type of the item.
        if (inspector.CurrentItem is AppointmentItem)
        {
            return new AppointmentItemWrapper(inspector);
        }

        // No wrapper is found.
        return null;
    }
}

// Derive a wrapper for each message class/item type.
}
  

и вот пример переопределения

 internal class MailItemWrapper : InspectorWrapper
{
    // The Object instance behind the Inspector, which is the current item.

    public MailItemWrapper(Inspector inspector)
        : base(inspector)
    {
        // Get the item in the current Inspector.
        Item = (MailItem) Inspector.CurrentItem;

        // Register Item events.
        Item.Open  = Item_Open;
        Item.Write  = Item_Write;
    }

    public MailItem Item { get; private set; }

    // This method is called when the item is visible and the UI is initialized.
    // <param name="Cancel">When you set this property to true, the Inspector is closed.</param>
    private void Item_Open(ref bool Cancel)
    {
        // TODO: Implement something 
    }

    // This method is called when the item is saved.
    // <param name="Cancel">When set to true, the save operation is cancelled.</param>
    private void Item_Write(ref bool Cancel)
    {
        //TODO: Implement something 
    }

    // The Close method is called when the inspector has been closed.
    // Do your cleanup tasks here.
    // The UI is gone, cannot access it here.
    protected override void Close()
    {
        // Unregister events.
        Item.Write -= Item_Write;
        Item.Open -= Item_Open;

        // Release references to COM objects.
        Item = null;

        // Set item to null to keep a reference in memory of the garbage collector.
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}
  

и вот класс ThisAddIn

 public partial class ThisAddIn
{
    // Holds a reference to the Application.Inspectors collection.
    // Required to get notifications for NewInspector events.
    private Inspectors _inspectors;

    // A dictionary that holds a reference to the inspectors handled by the add-in.
    private Dictionary<Guid, InspectorWrapper> _wrappedInspectors;

    private void ThisAddInStartup(object sender, EventArgs e)
    {
        _wrappedInspectors = new Dictionary<Guid, InspectorWrapper>();
        _inspectors = Globals.ThisAddIn.Application.Inspectors;
        _inspectors.NewInspector  = WrapInspector;

        // Also handle existing Inspectors
        // (for example, double-clicking a .msg file).
        foreach (Inspector inspector in _inspectors)
        {
            WrapInspector(inspector);
        }
    }


    // Wrap an Inspector, if required, and store it in memory to get events of the wrapped Inspector.
    // <param name="inspector">The Outlook Inspector instance.</param>
    private void WrapInspector(Inspector inspector)
    {
        var wrapper = InspectorWrapper.GetWrapperFor(inspector);
        if (wrapper != null)
        {
            // Register the Closed event.
            wrapper.Closed  = WrapperClosed;
            // Remember the inspector in memory.
            _wrappedInspectors[wrapper.Id] = wrapper;
        }
    }

    // Method is called when an inspector has been closed.
    // Removes reference from memory.
    // <param name="id">The unique id of the closed inspector</param>
    private void WrapperClosed(Guid id)
    {
        _wrappedInspectors.Remove(id);
    }


    private void ThisAddInShutdown(object sender, EventArgs e)
    {
        // Clean up.
        _wrappedInspectors.Clear();
        _inspectors.NewInspector -= WrapInspector;
        _inspectors = null;
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }

    #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()
    {
        Startup  = ThisAddInStartup;
        Shutdown  = ThisAddInShutdown;
    }

    #endregion
}
  

Там должно быть достаточно, чтобы избавить людей от проблем, если ссылка отключена