2016-08-24 107 views
2

我正在處理現有的Excel VSTO插件,當用戶編輯MS Word文檔中嵌入的工作簿時會導致問題。在該環境中插件功能並不是必需的,但它會導致嵌入發生故障,即使客戶正在操作與外掛程序操作無關的文件。至少,我需要讓它不爲該工作簿自行初始化。我的VSTO Excel插件如何判斷工作簿是否嵌入Word文檔?

一些途徑我已經調查:

  1. Microsoft.Office.Interop.Excel.Workbook.Application的文件上寫着:「當沒有 使用對象限定符,該屬性返回Application對象 代表Microsoft Excel應用程序當與 對象限定符一起使用時,此屬性返回一個應用程序對象, 表示指定對象的創建者(您可以使用此OLE自動化對象的此 屬性返回n應用 那個對象)。「這聽起來很有希望,但是,我不明白 什麼「與對象限定符」意味着在C#的上下文中。
  2. This link建議檢查命令行參數。但是,如果我單獨打開Excel,然後用嵌入式Excel對象打開我的Word文檔,則Word使用相同的實例進行嵌入,而命令行參數將不包含「-embedded」標誌。
  3. 我很想強制OLE使用Excel的新實例(而不是重用現有的獨立實例),但我無法弄清楚如何做到這一點。

由於Excel的單個實例可以同時託管嵌入工作簿和獨立工作簿,因此此信息需要位於工作簿級別。

+0

你有沒有科幻指出這一點?我想在Word文檔中禁用嵌入式Excel工作簿的插件。 – tjsmith

+0

對不起,但我們還沒有回到這個問題。不過,我仍然對解決方案感興趣。 –

回答

0

您可以通過檢查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; 

+0

調用**工作簿。容器**不適用於我。無論工作簿是獨立的Excel應用程序還是Word中嵌入的工作簿,它總是會拋出異常-2146822566(0x800A165A)。我的系統有什麼不同?我正在使用Office 2016. –

+0

也許工作簿嵌入的方式有所不同?只是猜測雖然...你可以分享一個樣本文件嗎? –

+0

我正在兩種情況下工作:(1)運行Excel並製作一張空白工作表。 (2)運行Word,在「插入」功能區中選擇「Object ...」,選擇「新建」和「Microsoft Excel工作表」。然後選擇新創建的Excel工作表。請注意,我得到的是與您記錄的不同的錯誤代碼。我讀過Workbook.Container在「Partially Trusted Assemblies」中不可用的地方。我試圖研究這可能是一個促成因素。 –

0

此作品告訴你,如果工作簿是嵌入的OLE對象(其他回答檢查workbook.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 
    } 
} 
} 
+0

我會試試這個......但是我可能需要一段時間才能回到這個問題上。 –

+0

嗨。上述工作對你有用嗎?我只是試圖按照描述來實現IsEmbedded,但沒有運氣。我正在使用Office 2016 –

+0

...但是,我在工作簿打開處理程序中使用它,它不起作用。如果我在關閉處理程序中使用它,它會起作用我需要在打開時檢測它。 –

相關問題