【问题标题】:How can my VSTO Excel addin tell if a workbook is embedded in a word document?我的 VSTO Excel 插件如何判断工作簿是否嵌入在 Word 文档中?
【发布时间】:2016-08-24 23:10:13
【问题描述】:

我正在处理现有的 Excel VSTO 插件,当用户编辑嵌入在 MS Word 文档中的工作簿时,该插件会导致问题。在该环境中插件功能不是必需的,但它会导致嵌入出现故障,即使客户正在操作与插件操作无关的文件。至少,我需要让它不为该工作簿初始化。

我调查过的一些途径:

  1. Microsoft.Office.Interop.Excel.Workbook.Application 的文档中写道:“当不使用时 对象限定符,此属性返回一个 Application 对象 代表 Microsoft Excel 应用程序。当与 对象限定符,此属性返回一个 Application 对象,该对象 表示指定对象的创建者(可以用这个 属性与 OLE 自动化对象返回应用程序 那个对象)。” 这听起来很有希望,但是,我不明白 “带有对象限定符”在 C# 的上下文中是什么意思。
  2. This link 建议检查命令行参数。但是,如果我单独打开 Excel,然后打开嵌入了 Excel 对象的 Word 文档,Word 将使用相同的实例进行嵌入,并且命令行参数将不包含“-embedded”标志。
  3. 我很想强制 OLE 使用新的 Excel 实例(而不是重复使用现有的独立实例),但我也不知道该怎么做。

由于 Excel 的单个实例可以同时托管嵌入式和独立工作簿,因此此信息需要在工作簿级别。

【问题讨论】:

  • 你有没有想过这个问题?我想禁用 Word 文档中嵌入 Excel 工作簿的插件。
  • 抱歉,我们还没有回复这个问题。但是,我仍然对解决方案感兴趣。

标签: c# excel ms-word vsto ole


【解决方案1】:

这可以告诉您工作簿是否是嵌入式 OLE 对象(检查工作簿的另一个答案。容器在 Office 2016 上对我不起作用): https://theofficecontext.com/2013/04/10/how-to-determine-if-an-excel-workbook-is-embedded-and-more/

public static class ExcelExtensionMethods
{

[DllImport("ole32.dll")]
static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);

/// <summary>
/// WORKBOOK EXTENSION METHOD
/// Checks to see if the Workbook is embeeded inside of 
/// another ActiveX Document type, sy=uch as Word or Excel.
/// </summary>
/// <param name="PobjWb"></param>
/// <returns></returns>
public static bool IsEmbedded(this Excel.Workbook PobjWb)
{
    if (PobjWb.Path == null || PobjWb.Path.Length == 0)
    {
        try
        {
            // requires using Microsoft.VisualStudio.OLE.Interop;
            // and you have to manually add this to reference from here:
            // C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Microsoft.VisualStudio.OLE.Interop.dll
            IOleObject LobjOleObject = ((object)PobjWb) as IOleObject;
            IOleClientSite LobjPpClientSite;
            // get the client site
            LobjOleObject.GetClientSite(out LobjPpClientSite);
            // if there is one - we are embedded
            if (LobjPpClientSite != null)
            {
                return true;
            }
            else
            {
                // not embedded
                return false;
            }
        }
        catch (Exception ex)
        {
            // exception
            Debug.Print(ex.ToString());
            return false;
        }
        finally { }
    }
    else
    {
        // not embedded
        return false;
    }
}

/// <summary>
/// WORKBOOK EXTENSION METHOD
/// This method return the name of the class that we
/// are embedded inside of.
/// If we are not embedded it return null.
/// If there is any exception it return null.
/// If the container cannot be accessed it returns UNKNOWN.
/// </summary>
/// <param name="PobjWb"></param>
/// <returns></returns>
public static string EmbedClassName(this Excel.Workbook PobjWb)
{
    try
    {
        IOleObject LobjOleObject = ((object)PobjWb) as IOleObject;
        IOleClientSite LobjPpClientSite;
        // get the client site
        LobjOleObject.GetClientSite(out LobjPpClientSite);
        if (LobjPpClientSite != null)
        {
            IOleContainer LobjPpContainer;
            LobjPpClientSite.GetContainer(out LobjPpContainer);
            if (LobjPpContainer != null)
            {
                return LobjPpContainer.GetType().Name;
            }
            else
            {
                // something wrong - container is not valid
                return "UNKNOWN";
            }
        }
        else
        {
            // not embedded
            return null;
        }
    }
    catch (Exception ex)
    {
        Debug.Print(ex.ToString());
        return null; // failed
    }
}

/// <summary>
/// WORKBOOK EXTENSION METHOD
/// Get the full path to the file that the workbook is embedded 
/// inside of. 
/// If we are not embeeded then this will return null.
/// If we are embedded but there are issues with the container
/// or an exception occurs, it will return null.
/// Otherwise we get the full path and filename.
/// </summary>
/// <param name="PobjWb"></param>
/// <returns></returns>
public static string EmbedMoniker(this Excel.Workbook PobjWb)
{
    try
    {
        IOleObject LobjOleObject = ((object)PobjWb) as IOleObject;
        IOleClientSite LobjPpClientSite;
        // get the client site
        LobjOleObject.GetClientSite(out LobjPpClientSite);
        if (LobjPpClientSite != null)
        {
            IOleContainer LobjPpContainer;
            LobjPpClientSite.GetContainer(out LobjPpContainer);
            if (LobjPpContainer != null)
            {
                // get the moniker
                IMoniker LobjMoniker;
                LobjPpClientSite.GetMoniker((uint)OLEGETMONIKER.OLEGETMONIKER_FORCEASSIGN,
                                            (uint)OLEWHICHMK.OLEWHICHMK_OBJFULL,
                                            out LobjMoniker);
                if (LobjMoniker != null)
                {
                    // now pull the moniker display name
                    // this will be in the form of PATH!Context
                    string LstrDisplayName;
                    IBindCtx LobjCtx = null;
                    CreateBindCtx(0, out LobjCtx); // required (imported function)
                    LobjMoniker.GetDisplayName(LobjCtx, null, out LstrDisplayName);
                    // remove context is exists
                    if (LstrDisplayName.Contains("!"))
                    {
                        string[] LobjMonikerArray = LstrDisplayName.Split('!');
                        // return the first part - which should be the path
                        return LobjMonikerArray[0];
                    }
                    else
                    {
                        // return full display name
                        return LstrDisplayName;
                    }
                }
                else
                {
                    // no moniker value
                    return null;
                }
            }
            else
            {
                // something wrong - container is not valid
                return null;
            }
        }
        else
        {
            // not embedded
            return null;
        }
    }
    catch (Exception ex)
    {
        Debug.Print(ex.ToString());
        return null; // failed
    }
}
}

【讨论】:

  • 我会试试这个...但我可能需要一段时间才能重新解决这个问题。
  • 嗨。以上对你有用吗?我只是尝试按照描述实现 IsEmbedded,但没有运气。我正在使用 Office 2016
  • ... 但是我在工作簿打开处理程序中使用它,但它不起作用。如果我在 Close 处理程序中使用它,它可以工作。我需要在打开时检测它。
【解决方案2】:

您可以通过检查Workbook.Container 属性来确定工作簿是否嵌入到另一个应用程序中。如果嵌入了工作簿,它将包含包含嵌入工作簿的 Word Document 对象。否则调用该属性将引发异常,因此请确保将检查包装到 try-catch 块中:

public bool IsEmbedded(Workbook workbook)
{
    try
    {
        // via the container you get a handle to the parent Word document object
        var container = workbook.Container;
        return true;
    }
    catch (COMException ex)
    {
        if (ex.ErrorCode == -2146822566)
        {
            // Exception message is: 
            // "This property is only available if the document is an OLE object."   
            return false;
        }

        throw;
    }
}

可以依赖Workbook.PathWorkbook.Name 属性。

我在检查嵌入式 Excel 工作簿的这些属性时得到以下结果:

// this is empty for an embedded workbook
Application.Workbooks[1].Path; 

// this contains the string "Worksheet in <document name>.docx"
Application.Workbooks[1].Name;

【讨论】:

  • 调用 workbook.Container 对我不起作用。无论工作簿是独立的 Excel 应用程序还是嵌入在 Word 中的工作簿,它总是抛出异常 -2146822566 (0x800A165A)。我的系统可能有什么不同?我正在使用 Office 2016。
  • 也许嵌入工作簿的方式不同?只是猜测......你能分享一个示例文档吗?
  • 我正在处理两种情况:(1)运行 Excel 并制作一个空白工作表。 (2) 运行 Word,在“插入”功能区选择“对象...”,选择“新建”和“Microsoft Excel 工作表”。然后选择新创建的 Excel 工作表。请注意,我收到的错误代码与您记录的不同。我在某处读到 Workbook.Container 在“部分受信任的程序集”中不可用。我正在尝试研究这是否是一个促成因素。
【解决方案3】:

我在 Word 中嵌入 Excel 时遇到了同样的问题。并且解决方案一直是Marshal.ReleaseComObject所有对象都在每个事件函数的末尾。

例子:

private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
   // code
   Marshal.ReleaseComObject(sender);
   Marshal.ReleaseComObject(e);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多