<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      C# 開發 Office 和 WPS COM 加載項

      一、實現接口 IDTExtensibility2

      這是實現 Office COM 加載項最基本的接口

      添加 COM 引用 Microsoft Add-In Designer 即可

      對應文件 Extensibility.dll 只包含 IDTExtensibility2 接口其中和用到的枚舉 ext_ConnectMode、ext_DisconnectMode,
      可以減少模塊引用自行復制代碼到自己項目中,注意 IDTExtensibility2 不可被混淆

      ? 注意:開發 Office 或 WPS COM 加載項添加 COM 引用時,需要安裝對應的套件才能找到相關的 COM 組件,添加 WPS COM 引用時會受到兩者安裝的先后順序和管理員權限影響,導致無法添加引用,若 VS 報錯無法添加,需要卸載 Office 才能順利添加。但下文會提到僅需引用其中一套 COM 組件即可同時兼容 Office 和 WPS

      #if BrandName1
      namespace BrandName1 // 品牌1
      #else
      namespace BrandName2 // 品牌2
      #endif
      {
          [Obfuscation] // 不可被混淆
          [ComVisible(true)] // COM 組件類可見, 并且類型要設為公開 public
          [Guid("XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")] // CLSID
          // [ProgId("BrandName1.OfficeAddIn")] // Office COM 加載項的 ProgID 須與類全名一致
          public class OfficeAddIn : IDTExtensibility2
          {
              public void OnConnection(
                  object application, ext_ConnectMode connectMode,
                  object addInInst, ref Array custom)
              {
                  MessageBox.Show("OnConnection"); // 注冊成功的加載項將會在對應應用啟動時彈窗
              }
      
              // 其他 IDTExtensibility2 的接口方法...
          }
      }
      

      ? 注意:Office COM 加載項須保證類的 ProgID 與類全名完全匹配, ProgID 特性未設置時默認使用類的全名,故也無需設置;并且類不可被混淆,被其繼承的接口也不可被混淆

      ProgID 與產品和對應功能相關,文件關聯也會用到,建議名稱是 .,故示例中以 BrandName1 為名稱空間,OfficeAddIn 為類名,那么 ProgID 就是 BrandName1.OfficeAddIn。為區分品牌,在品牌條件編譯中使用不同的名稱空間,而不是不同的類名,這樣更符合規范,也更好編寫注冊的代碼

      二、注冊 Office COM 加載項

      COM CLSID 和 Office 產品的注冊表都有 HKCU、HKLM 和 64、32位的項,為了提高兼容性,可在這些注冊表項下都添加上注冊信息

      注冊 COM 組件

      C# 注冊 COM 組件一般通過調用 RegAsm.exe 文件來注冊,區分位數和運行時版本

      %windir%\Microsoft.NET\Framework[64]_"ver"_\RegAsm.exe MyCOM.dll /codebase [/u]

      RegAsm.exe 作用就是添加注冊表項,避免系統缺失該文件,也為了添加日志輸出,可自行寫注冊表實現

      {HKCU|HKLM}\Software\Classes
          ProgID
              ● "" = 'ProgID'
              CLSID
                  ● "" = 'CLSID'
          [Wow6432Node\]CLSID\'CLSID'
              ● "" = 'ProgID'
              Implemented Categories\{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}
              InprocServer32
                  ● "" = "mscoree.dll"
                  ● "Assembly" = 'Assembly.FullName'
                  ● "Class" = 'ProgID'
                  ● "CodeBase" = 'Assembly.CodeBase'
                  ● "RuntimeVersion" = 'Environment.Version' 
                  ● "ThreadingModel" = "Both"
              ProgId
                  ● "" = 'ProgID'
      

      ? 注意:RegAsm.exe 注冊方式會用到反射,如果不將引用到的程序集文件放到同目錄下,并且系統未注冊 COM 類繼承的接口時,會出錯導致注冊失敗。如果注冊方式和 RegAsm.exe 一樣會用到類型本身,為避免用戶未安裝 COM 組件相關的應用,需要打包引用到的程序集

      ? 注意:同一個 COM 組件項目創建不同品牌的程序集并注冊時,如果兩個程序集文件名相同、簽名相同、版本相同,則會導致兩者程序集全名相同,導致系統無法區分。區分方式是三者至少有一個不同,最簡單的方式就是條件編譯設置不同版本號

      ? 注意:為提高兼容性,目標平臺選擇 AnyCPU 即可兼容 64/32 位系統和軟件。作為 COM 組件運行時,是作為被 .NET 虛擬機進程引用的程序集來運行的,只需將目標框架設為 .NET Framework 3.5, 不需要 app.config 文件就可以兼容 3.5 和 4.0,無需編譯多個框架版本。支持 .dll 和 .exe 文件,只要是 .NET 程序集就可以,如果是可將自身注冊為 COM 組件 exe,那在注冊時還是需要 app.config 的

      添加到 Office 加載項列表

      需要在加載項列表下新建加載項類 ProgID 同名子項,并添加三個必要的注冊表鍵值

      {HKCU|HKLM}\Software\[Wow6432Node\]Microsoft\Office
          <app>
              AddIns
                  'ProgID'
                      ● FriendlyName = "加載項列表中顯示的友好名稱"
                      ● Description = "加載項列表中顯示的描述"
                      ● LoadBehavior = 3 (啟動時連接和加載)
      

      另外還可以添加 CommandLineSafe = 1, 指示命令行操作安全,可能可以減少彈窗警告

      經過這兩步注冊示例插件后,啟動對應的 Office 應用時,就會彈出消息框,驗證注冊成功了

      三、實現接口 IRibbonExtensibility

      這個接口用于在 Office 應用的 Ribbon 中添加自定義 UI

      添加 COM 引用 Microsoft Office  Object Library 即可, 是 Office 版本號

      為提高兼容性,可以安裝 Office 2007 獲取到 12.0 版本的 COM,并將對應的文件 Office.dll 復制到項目目錄中,并修改引用為相對文件,避免在其他未安裝 Office 2007 的電腦上無法生成。注意此接口也要被加載項類繼承,故不可被混淆

      此接口只有一個 GetCutsomUI 的方法,需要返回 XML 格式的字符串

      為了代碼可讀性,建議使用編寫和加載 XML 資源文件的方式

      并且在 VS 中編寫 XML 添加名稱空間后在編寫元素屬性時將會有候選詞列表,十分方便

      <?xml version="1.0" encoding="utf-8"?>
      <customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui">
        <ribbon>
          <tabs>
            <tab id="TestTab" getLabel="GetLabel">
              <group id="TestGroup" getLabel="GetLabel">
                <button id="TestButton" size="large"
                  onAction="OnButtonPressed"
                  getLabel="GetLabel"
                  getImage="GetImage"/>
              </group>
            </tab>
          </tabs>
        </ribbon>
      </customUI>
      
      public class OfficeAddIn : IDTExtensibility2, IRibbonExtensibility
      {
          public string GetLabel(IRibbonControl control)
          {
              switch(control.ID)
              {
                  case "TestTab": return "Test Tab";
                  case "TestGroup": return "Test Group";
                  case "TestButton": return "Test Button";
              }
              return null;
          }
      
          public {Bitmap|IPictureDisp} GetImage(IRibbonControl control)
          {
              // 返回控件圖像,支持 Bitmap 或 IPictureDisp 類型返回值
          }
      
          public void OnButtonPressed(IRibbonControl control)
          {
              MessageBox.Show("Test Button Clicked!");
          }
      }
      

      CustomUI 注意事項

      建議攜帶 XML 聲明部分指定utf-8編碼,否則如果有中文會亂碼

      customUI元素中的名稱空間,年月可以用2009/072006/01,但 Office 2007 不支持解析前者

      控件的文本、圖像、懸浮提示語等,都可使用對應的屬性labelimage在 XML 中直接設置。也可以使用對應的回調方法getLabelgetImage。使用回調方法的方式需要在加載項類中聲明同名公開方法,比如 XML 中編寫getLabel="GetLabel",C# 中就須編寫對應的public string GetLabel (IRibbonControl control)方法,類似于 WPF XAML 的事件綁定,支持多個控件使用同一個方法并根據控件的 id 返回合適的值

      第 3 條中屬性和回調方法互斥,只允許使用其中一個。另外圖像還可使用內置圖像屬性imageMso ,與imagegetImage也是互斥的,比如 imageMso="FileSaveAs"使用內置的另存為圖像

      如果使用了 dynamicMenu 控件,其 getContent 方法也需要返回 XML 格式字符串,但與第 1 條不同,不能有 XML 聲明部分,否則解析失敗

      大小寫敏感,大小寫錯誤會導致解析失敗

      使用透明背景圖像

      CustomUI 中控件的getImage方法支持直接返回Bitmap類型,Office 支持透明背景的Bitmap,但 WPS 不支持,會用淺灰色的背景填充。這里可以轉換并返回IPictureDisp類型

      另外值得一提的是,Office 在切換深色主題后,黑灰單色圖像還會自動轉換為白色圖像,WPS 沒有這個機制

      IPictureDisp 在 COM 組件 OLE Automation 中定義,一般在添加 Microsoft Office  Object Library 引用時會自動添加上,對應文件是 stdole.dll,我們只需要用到 IPictureDisp 接口,同樣可以減少模塊引用自行復制代碼到自己項目中

      [DllImport("oleaut32.dll", ExactSpelling = true, PreserveSig = false)]
      static extern IPictureDisp OleCreatePictureIndirect(
          ref PictDesc pictdesc,
          [MarshalAs(UnmanagedType.LPStruct)] Guid iid,
          [MarshalAs(UnmanagedType.Bool)] bool fOwn);
      
      struct PictDesc
      {
          public int cbSizeofstruct;
          public int picType;
          public IntPtr hbitmap;
          public IntPtr hpal;
          public int unused;
      }
      
      public static IPictureDisp CreatePictureIndirect(Bitmap bitmap)
      {
          var picture = new PictDesc
          {
              cbSizeofstruct = Marshal.SizeOf(typeof(PictDesc)),
              picType = 1,
              hbitmap = bitmap.GetHbitmap(Color.Black), // 創建純透明底色位圖
              hpal = IntPtr.Zero,
              unused = 0,
          };
          return OleCreatePictureIndirect(ref picture, typeof(IPictureDisp).GUID, true);
      }
      

      Bitmap.GetHbitmap有無參和傳參Color兩個重載,無參重載在內部傳參Color.LightGray調用另一重載,這應該和直接返回Bitmap在 WPS 中會有淺灰色填充相關。
      需要注意的是,GetHbitmap方法內部不會使用到顏色的 Alpha 值, 創建純透明背景圖像句柄,應該使用Color.Black 255,0,0,0而不是Color.Transparent``0,255,255,255

      CustomUI 刷新控件

      1. 利用customUI元素的onload回調方法,在 C# 中記錄IRibbonUI對象,可調用其Invalidate方法刷新整個 UI,或者調用InvalidateControl(string id)根據 id 刷新指定控件
      public class OfficeAddIn : IDTExtensibility2, IRibbonExtensibility
      {
          IRibbonUI ribbon;
      
          public void OnCustomUILoad(IRibbonUI ribbon)
          {
              this.ribbon = ribbon;
          }
      
          internal void Invalidate()
          {
              ribbon?.Invalidate();
          }
      
          internal void InvalidateControl(string id)
          {
              ribbon?.InvalidateControl(id);
          }
      }
      
      1. dynamicMenu控件invalidateContentOnDrop="true"可在每次展開時重新觸發getContent刷新內容

      四、Office 互操作能力

      需要添加引用對應 Office 應用的互操作庫,在 VS 中可以很方便的跳轉 MSDN 文檔

      添加 COM 引用 Microsoft   Object Library 即可

      下文演示 Office 導出 PDF 能力,僅作演示,另外需要釋放 COM 對象

      ExportAsFixedFormat 方法有很多可選參數,支持設置打印頁數、包含文檔信息、生成書簽等

      ? 注意:Office 2007(只有 32 位版本)導出 PDF/XPS 會提示未安裝此功能時,需要用到 Office 2010 才有的 EXP_PDF.dll 和 EXP_XPS.dll 文件,復制到 Office 2007 的共享目錄即可

      %CommonProgramFiles[(x86)]%\Microsoft Shared\OFFICE12

      Word 導出 PDF

      using Microsoft.Office.Interop.Word;
      
      public class OfficeAddIn : IDTExtensibility2, IRibbonExtensibility
      {
          Application app;
      
          public void OnConnection(
              object application, ext_ConnectMode connectMode, 
              object addInInst, ref Array custom)
          {
              if (application is Application)
                  app = (Application)Application;
          }
      
          public void OnButtonPressed(IRibbonControl control)
          {
              app?.ActiveDocument?.ExportAsFixedFormat(fileName, WdExportFormat.wdExportFormatPDF);
          }
      }
      

      Excel 導出 PDF

      using Microsoft.Office.Interop.Excel;
      // 工作簿
      app?.ActiveWorkbook?.ExportAsFixedFormat(XlFixedFormatType.xlTypePDF, fileName);
      
      // 工作表
      (app?.ActiveSheet as Worksheet)?.ExportAsFixedFormat(XlFixedFormatType.xlTypePDF, fileName);
      
      // 圖表, WPS 不支持
      app.ActiveChart?.ExportAsFixedFormat(XlFixedFormatType.xlTypePDF, fileName);
      
      // 框選區域
      var range = app.Selection as Range;
      var sheet = range.Worksheet;
      var area = sheet.PageSetup.PrintArea;
      sheet.PageSetup.PrintArea = range.Address; // 設置打印區域為選定區域
      sheet.ExportAsFixedFormat(XlFixedFormatType.xlTypePDF, fileName);
      sheet.PageSetup.PrintArea = area; // 還原打印區域
      

      PowerPoint 導出 PDF

      using Microsoft.Office.Interop.PowerPoint;
      
      app?.ActivePresentation?.ExportAsFixedFormat(fileName, PpFixedFormatType.ppFixedFormatTypePDF);
      

      Publisher 導出 PDF

      using Microsoft.Office.Interop.Publisher;
      
      app?.ActiveDocument?.ExportAsFixedFormat(PbFixedFormatType.pbFixedFormatTypePDF, fileName);
      

      Outlook 導出郵件為 PDF

      using Microsoft.Office.Interop.Outlook;
      using Microsoft.Office.Interop.Word;
      
      var mailItem = outlook?.ActiveExplorer()?.Selection?.OfType<MailItem>()?.FirstOrDefault();
      var inspector = mailItem?.GetInspector;
      var document = inspector?.WordEditor as Document;
      document?.ExportAsFixedFormat(fileName, WdExportFormat.wdExportFormatPDF);
      // GetInspector 會打開一個隱藏窗口,比較吃內存,需要及時關閉
      inspector?.Close(OlInspectorClose.olPromptForSave);
      

      五、實現 WPS COM 加載項

      須在注冊 Office COM 加載項基礎上(包括添加到 Office 加載項列表),另外添加到 WPS 加載項列表

      添加到 WPS 加載項列表

      Word 對應 WPS,Excel 對應 ET,PowerPoint 對應 WPP,不區分 64/32位

      HKCU\Software\kingsoft\office
          {WPS|ET|WPP}
              AddinsWL
                  'ProgID' = ""
      

      Office 與 WPS COM 組件對應表

      ? 注意:WPS 和 Office 官方為了互相兼容,Office、Word、Excel、PowerPoint 相關的 COM 接口使用相同的 CLSID。如果插件需要兼容兩者,對應的互操作庫文件只需要一組,因程序集內名稱空間不同,且用戶基本只會安裝其中一套,須復制互操作庫文件到運行目錄,否則無法同時兼容

      Office WPS
      Microsoft Add-In Designer
      Extensibility.dll
      Kingsoft Add-In Designer
      Interop.AddInDesignerObjects.dll
      Microsoft Office  Object Library
      Office.dll
      Upgrage WPS Office  Object Library
      Interop.Office.dll
      Microsoft Word  Object Library
      Microsoft.Office.Interop.Word.dll
      Upgrade Kingsoft WPS  Object Library
      Interop.Word.dll
      Microsoft Excel  Object Library
      Microsoft.Office.Interop.Excel.dll
      Upgrage WPS Spreadsheets  Object Library
      Interop.Excel.dll
      Microsoft PowerPoint  Object Library
      Microsoft.Office.Interop.PowerPoint.dll
      Upgrage WPS Presentation  Object Library
      Interop.PowerPoint.dll

      六、卸載清理注冊表

      除了清理上文中添加的 COM 組件和加載項的注冊表,還可以清理以下相關的注冊表:

      1. HKCU\Software\Microsoft\Office\<app>\AddinsData插件數據

      2. HKCU\Software\Microsoft\Office\<ver>\Common\CustomUIValidationCacheCustomUI 校驗緩存

      3. HKCU\Software\Microsoft\Office\<ver>\<app>\Addins版本插件列表

      4. HKCU\Software\Microsoft\Office\<ver>\<app>\AddInLoadTimes版本加載次數

      5. HKCU\Software\Microsoft\Office\<ver>\<app>\Resiliency\NotificationReminderAddinDataOffice 禁用通知

      七、其他問題

      未加載,加載 COM 加載項時出現運行錯誤

      這是一個比較令人頭疼的問題,可能原因有很多,但 Office 沒有報錯日志,導致很難排查問題

      微軟官方博客 給出了一些解答,個人也復現了一些情況:

      • 部署問題:COM 組件注冊表內容缺失項或鍵值,需要注意 COM 組件與 Office 加載項注冊表的位數

      • 運行問題:在 Outlook 中比較明顯,本身就啟動緩慢卡頓,切忌在啟動時調用 Sleep 函數,輕則 Office 直接提示建議禁用插件,重則直接出現未加載的問題

      Outlook 退出前操作

      Outlook 16.0(其他版本未測試)退出時不會觸發 OnBeginShutdownOnDisconnection,原因未知,應該是 Outlook 自己的 Bug,故 Outlook 插件不要在這兩個方法中進行退出前操作

      經過測試,程序退出時會觸發System.Windows.Forms.Application.ThreadExit,但是不會觸發(來不及?)AppDomain.CurrentDomain.ProcessExit,可以利用前者來進行退出前操作,比如保存配置和釋放資源

      Office 應用關閉后進程不結束

      出現此問題一般是 COM 對象資源未釋放干凈,但是頻繁使用 Office 互操作很難保證所有 COM 對象都及時正確釋放。為了讓進程正確退出,不可使用Process.Kill等強制方法手動結束進程,一是強制結束進程可能會導致下次打開文檔時會提示文檔保存異常,二是插件可在程序運行中被手動卸載,可以使用卸載當前應用程序域的方式友好解決問題

      public void OnDisconnection(ext_DisconnectMode removeMode, ref Array custom)
      {
          try
          {
              AppDomain.Unload(AppDomain.CurrentDomain);
          }
          catch (CannotUnloadAppDomainException)
          {
              // ignored
          }
      }
      

      相關資料

      如何使用 Visual C# .NET 生成 Office COM 加載項 - Office

      [MS-CUSTOMUI]: CustomUI |Microsoft 學習

      COM Add-In 加載失敗疑難解答 |Microsoft 學習

      posted @ 2025-03-31 20:06  藍點lilac  閱讀(1404)  評論(3)    收藏  舉報
      主站蜘蛛池模板: 熟女精品国产一区二区三区| 亚洲AV乱码毛片在线播放| 无码伊人66久久大杳蕉网站谷歌 | 亚洲av激情久久精品人| 国产精品久久久久aaaa| av综合亚洲一区二区| 少妇人妻偷人偷人精品| 亚洲精品国产精品国自产| 大尺度国产一区二区视频| 国产特级毛片aaaaaa毛片| 久久se精品一区二区三区| 麻豆精品一区二区视频在线| 国产精品免费看久久久无码| 伦理片午夜视频在线观看| 老司机午夜精品视频资源| 人成午夜免费大片| 日韩一区二区三区一级片| 91久久夜色精品国产网站| 国产精品无码a∨精品| 久久天天躁狠狠躁夜夜躁2020 | 广水市| 国产SM重味一区二区三区| 国产高清在线精品一区不卡| 国产成人黄色自拍小视频| 亚洲色大成永久WW网站| 国产精品无码素人福利不卡| 在线播放亚洲成人av| 岗巴县| 91午夜福利在线观看精品| 亚洲免费观看视频| 丰满人妻被黑人猛烈进入| 欧美日韩国产图片区一区| 日本无产久久99精品久久| 国产黄色大片网站| 超碰伊人久久大香线蕉综合| 亚洲精品二区在线播放| 亚洲人成网站18禁止无码| 一级片一区二区中文字幕| 成人天堂资源www在线| 国产福利微视频一区二区| 人妻丰满熟妇无码区免费|