最近做一個vsto的項目,涉及到Form程序調用vsto動態庫,弄了半天,搜了很多資料終於搞定了,把積累寫下來備以后用。
相關網址:
https://stackoverflow.com/questions/10875278/vsto-add-ins-comaddins-and-requestcomaddinautomationservice
https://blogs.msdn.microsoft.com/andreww/2008/08/11/why-your-comaddin-object-should-derive-from-standardolemarshalobject/
https://blogs.msdn.microsoft.com/andreww/2007/01/15/vsto-add-ins-comaddins-and-requestcomaddinautomationservice/
Demo:
1. 建立一個word外接程序(addin)
我的demo建的是WordVSTOTest工程,建好以后在addin.cs文件中添加一個類變量和一個函數。這個函數是必須的。
namespace WordVSTOTest { public partial class ThisAddIn { private AddinUtilities addinUtilities; protected override object RequestComAddInAutomationService() { if (addinUtilities == null) { addinUtilities = new AddinUtilities(); } return addinUtilities; } } }
注意到AddinUtilities 沒有定義,是的,這是個自定義類,名字隨便,但要保持一致,里面要封裝你要導出的供外部調用的函數。
2. 添加一個類
demo的類名叫AddinUtilities,添加如下代碼:
using System.Runtime.InteropServices;
namespace WordVSTOTest { [ComVisible(true)] [InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface IAddinUtilities { void test(); } [ComVisible(true)] [ClassInterface(ClassInterfaceType.None)] public class AddinUtilities : StandardOleMarshalObject, IAddinUtilities { void test() { MessageBox.Show("Hello World"); } } }
這里定義一個接口類型,接口類型里面的函數就是要導出供外部調用的函數,需要什么函數就些什么函數,和普通函數無區別,然后我們的AddinUtilities類要繼承這個接口,最后依次實現定義的函數就可以了。我這里是導出了test函數,簡單彈個框。
3. 編譯
這個編譯需要設置一下,不然會有很多莫名其妙的錯誤,首先vs要用管理員啟動,然后轉到工程屬性-->build,在“輸出”欄有個 “為COM互操作注冊”的復選框,要勾選這個,最后編譯。編譯過程中如果要提示還有類似沒有注冊的錯誤,要用regasm.exe 注冊一下就行了。電腦里搜索到regasm.exe所在的目錄,cmd下轉到該目錄,使用命令:regasm.exe dll絕對路徑 /參數。 編譯好的dll要在winForm工程里面使用。
好了vsto這邊的工作就做完了,下面轉到我們的Form測試工程。
4. 建立一個WinForm工程
Demo為WinFormTest工程,建好以后,在form上拖一個button控件,雙擊button直接轉到click函數處:寫入一下代碼:
public Word.Application app; public IAddinUtilities utils; public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { app = new Word.Application(); string str = app.Name; app.Visible = false; object addinName = "WordVSTOTest"; COMAddIn addin = app.COMAddIns.Item(ref addinName); utils = (IAddinUtilities)addin.Object; utils.test(); //如果沒有這個Quit的話,任務管理器的WINWORD.exe不會退出,越來越多。 ((Word._Application)app).Quit(); System.Runtime.InteropServices.Marshal.FinalReleaseComObject(app); }
注意工程需要using以下幾項:
using WordVSTOTest;
using Word = Microsoft.Office.Interop.Word;
using Microsoft.Office.Core;
引入這些后才可以編譯通過。
簡單看一下工程截圖:
查看運行結果:
5. 結束。
理解這個調用過程還需要對COM有所了解,不明白原理,抄來抄去到時候出現bug也難排查,就到這里吧。