如何在Outlook 2013插件中可靠地获取联系人上下文菜单的对象?

时间:2015-04-30 14:11:35

标签: c# vsto outlook-addin outlook-2013

我正在the example in this article之后的Outlook 2013中为联系的上下文菜单添加一个条目。这是XML:

<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="Ribbon_Load">
  <contextMenus>
    <contextMenu idMso="ContextMenuContactItem">
      <button id="MyContextMenuContactItem" label="Do something..." onAction="OnDoSomething"  insertAfterMso="DialMenu"/>
    </contextMenu>
  </contextMenus>
</customUI>

该条目正确显示在菜单中,当我单击它时,我的事件处理程序将被执行:

public void OnDoSomething(IRibbonControl control)
{
    object context = control.Context;
    System.Diagnostics.Debug.WriteLine(context.GetType());
    if ((context as IMsoContactCard) != null) System.Diagnostics.Debug.WriteLine("IMsoContactCard");
    if ((context as ContactItem) != null) System.Diagnostics.Debug.WriteLine("ContactItem");
    if ((context as ContactCard) != null) System.Diagnostics.Debug.WriteLine("ContactCard");
    if ((context as _ContactItem) != null) System.Diagnostics.Debug.WriteLine("_ContactItem");
}

referenced article似乎表明上下文应该是IMsoContactCard,但这不是我得到的。打印出context.GetType()的行显示System.__ComObject

This article here似乎表明我应该能够将该对象转换为有用的东西,但是所有尝试将其转换为符合逻辑的东西(IMsoContactCardContactItem,{{ 1}},ContactCard)失败了。

为了回避问题,我尝试按照the instructions in this article跟踪当前选定的项目。这实际上运作得相当好,但需要注意的是当前所选项目并不总是上下文菜单适用的项目。

详细说明,我可以左键单击某个联系人,然后突出显示该选项并触发我的选择事件。如果我然后右键单击不同的联系人以显示上下文菜单而不先点击左键,那么该联系人将被概述但不会突出显示,而我的选择事件未被触发。发生这种情况时,我最终应用上下文菜单点击错误的联系人。

任何建议或指示都将不胜感激。感谢。

使用基于Eugene Astafiev

提供的信息的解决方案进行更新

根据下面提供的信息,我能够确定此特定回调的_ContactItem类型为Context。然后,我可以使用它来获取Microsoft.Office.Interop.Outlook.Selection,如下所示:

ContactItem

1 个答案:

答案 0 :(得分:2)

Context对象的类型取决于您单击的位置和上下文菜单类型。要获取基础类型,您需要执行以下操作:

  1. 将对象强制转换为IDispatch接口。
  2. 使用IDispatch接口的GetTypeInfo方法获取ITypeInfo接口。
  3. 使用ITypeInfo接口的GetDocumentation方法获取类型名称。

    public static string GetTypeName(object comObj)
    {
    
        if (comObj == null)
            return String.Empty;
    
        if (!Marshal.IsComObject(comObj))
            //The specified object is not a COM object
            return String.Empty;
    
        IDispatch dispatch = comObj as IDispatch;
        if (dispatch == null)
            //The specified COM object doesn't support getting type information
            return String.Empty;
    
        ComTypes.ITypeInfo typeInfo = null;
        try
        {
            try
            {
                // obtain the ITypeInfo interface from the object
                dispatch.GetTypeInfo(0, 0, out typeInfo);
            }
            catch (Exception ex)
            {
                //Cannot get the ITypeInfo interface for the specified COM object
                return String.Empty;
            }
    
            string typeName = "";
            string documentation, helpFile;
            int helpContext = -1;
    
            try
            {
                //retrieves the documentation string for the specified type description 
                typeInfo.GetDocumentation(-1, out typeName, out documentation,
                    out helpContext, out helpFile);
            }
            catch (Exception ex)
            {
                // Cannot extract ITypeInfo information
                return String.Empty;
            }
            return typeName;
        }
        catch (Exception ex)
        {
            // Unexpected error
            return String.Empty;
        }
        finally
        {
            if (typeInfo != null) Marshal.ReleaseComObject(typeInfo);
        }
    }
    

    }

  4. 有关详细信息,请参阅HowTo: get the actual type name behind System.__ComObject with Visual C# or VB.NET