c# - 我的 VSTO Excel 插件如何判断工作簿是否嵌入到 Word 文档中?

标签 c# excel ms-word vsto ole

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

我调查过的一些途径:

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

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

最佳答案

这用于告诉您工作簿是否是嵌入式 OLE 对象(检查工作簿的另一个答案。Container 在 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
    }
}
}

关于c# - 我的 VSTO Excel 插件如何判断工作簿是否嵌入到 Word 文档中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39134346/

相关文章:

c# - 使用 mongodb c# 驱动程序的本地化模式

java - 使用 POI 事件模型将工作表写入文本文件

c# - MS Word 2010 无法打开宏存储

java - 无法使用java读取pdf中的unicode字符

c# - 确定 foreach 中的顺序(pnl 中的面板 p)

c# - 搜索查询中的引号错误

c# - .NET 中显示数量发生变化时的事件?

excel - 如何使用 Pandas 按两列进行分组?

excel - 循环工作簿并将动态范围复制到主工作簿

c# - MS Word 加载项 : RIght click handler