我的VSTO Excel插件如何判断工作簿是否embedded在Word文档中?
我正在处理现有的Excel VSTO外挂程序,当用户编辑embedded在MS Word文档中的工作簿时,会导致问题。 即使在客户操纵与外挂程序无关的文件的情况下,插件在该环境中的function也不是要求的,而是导致embedded失效。 至less,我需要让它不为该工作簿自行初始化。
我调查了一些途径:
- Microsoft.Office.Interop.Excel.Workbook.Application的文档显示如下: “当使用没有对象限定符时,此属性返回一个代表Microsoft Excel应用程序的应用程序对象。当与对象限定符一起使用时,此属性返回一个应用程序对象它表示指定对象的创build者(您可以将此属性与OLE自动化对象一起使用来返回该对象的应用程序)。 这听起来很有希望,但是,我不明白什么“与对象修饰符”意味着在C#的上下文中。
- 这个链接build议检查命令行参数。 但是,如果我单独打开Excel,然后用embedded的Excel对象打开我的Word文档,Word使用相同的实例embedded,并且命令行参数将不包含“-embedded”标志。
- 我很想强制OLE使用Excel的新实例(而不是重用现有的独立实例),但我无法弄清楚如何做到这一点。
由于Excel的单个实例可同时托pipeembedded式和独立式工作簿,因此此信息需要处于工作簿级别。
您可以通过检查Workbook.Container
属性来确定工作簿是否embedded到另一个应用程序中。 如果embedded工作簿,它将包含包含embedded的工作簿的Word Document
对象。 否则调用该属性将会抛出一个exception,所以一定要将检查包装到一个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.Path
或Workbook.Name
属性。
对于我来说,当我检查embedded式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;
这适用于告诉你如果工作簿是一个embedded式的OLE对象(检查工作簿的其他答案.Container不适用于我在Office 2016上): https : //theofficecontext.com/2013/04/10/how-to -确定-IF-AN-Excel的工作簿是embedded-和-多/
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 } } }