我正在处理现有的 Excel VSTO 插件,当用户编辑嵌入在 MS Word 文档中的工作簿时,它会导致问题。这不是插件在该环境中运行的要求,但它会导致嵌入出现故障,即使客户正在操作与插件操作无关的文件。至少,我需要让它不为该工作簿自行初始化。
我调查过的一些途径:
- Microsoft.Office.Interop.Excel.Workbook.Application 的文档如下:“在没有使用时 一个对象限定符,此属性返回一个 Application 对象 表示 Microsoft Excel 应用程序。当与 对象限定符,此属性返回一个应用程序对象 代表指定对象的创建者(你可以使用这个 带有 OLE Automation 对象的属性以返回应用程序 那个对象)。” 这听起来很有希望,但是,我不明白 “带有对象限定符”在 C# 上下文中的含义。
- This link建议检查命令行参数。但是,如果我独立打开 Excel,然后打开带有嵌入式 Excel 对象的 Word 文档,Word 将使用相同的实例进行嵌入,并且命令行参数将不包含“-embedded”标志。
- 我很想强制 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/