本文假定你了解基本的编程事务、对在Visual Basic for Applications中编写Office宏有一些经验,可能在以前建立过某些Add-In。本文中的代码使用Office XP对象模型。
本文中的事务假定你已经从Visual Studio .NET新建项目对话框中建立了共享的Add-In。该新项目对话框将使用向导帮助你并建立基本的Add-In和安装项目。
决定应用程序类型
如果将建立的Add-In将在一个以上Office应用程序中载入,你可能需要决定Add-In在那种应用程序中运行。默认的Add-In项目有一个到Office库的引用,但并不是引用任意的特定应用程序库。在决定运行那种应用程序前,需要给将载入Add-In的应用程序添加一个引用。使用"添加引用"对话框的"COM"页来选择并给每个应用程序添加引用。
实现IDTExtensibility2接口的Connect类在OnConnection事件中有一个application参数。该参数表现正在运行的Office应用程序的实例,但是该参数为System.Object类型。为了更有用,需要把该引用转换成应用程序类型。该应用程序类型将根据载入Add-In的Office应用程序作更改。
下面的SetApplicationFields方法设置了两个类字段。该方法可以从Connect类的OnConnection方法中调用。
1、使用"添加引用"对话框的"COM"页给项目添加Microsoft Excel Object Library和Microsoft Word Object Library引用。
2、给Connect类添加两个类字段来表现Word和Excel应用程序实例。
' Visual Basic Dim wordApp As Word.Application Dim excelApp As Excel.Application // C# Word.Application wordApp = null; Excel.Application excelApp = null; |
3、把下面的方法添加到Connect类,它们用来设置Word和Excel应用程序引用。在应用程序载入时只需要一个字段不为空。
' Visual Basic Private Sub SetApplicationFields(ByVal application As Object) If TypeOf (application) Is Word.Application Then wordApp = CType(application, Word.Application) excelApp = Nothing ElseIf TypeOf (application) Is Excel.Application Then excelApp = CType(application, Excel.Application) wordApp = Nothing End If End Sub // C# private void SetApplicationFields(object application) { if (application is Word.Application) { wordApp = (Word.Application)application; excelApp = null; } else if (application is Excel.Application) { excelApp = (Excel.Application)application; wordApp = null; } } |
4、添加下面的代码到OnConnection方法,在add-in载入时设置该字段。
' Visual Basic Public Sub OnConnection(ByVal application As Object, _ ByVal connectMode As Extensibility.ext_ConnectMode, _ ByVal addInInst As Object, ByRef custom As System.Array) _ Implements Extensibility.IDTExtensibility2.OnConnection ' 为add-in 设置代码 SetApplicationFields(application) ' 更多代码 End Sub // C# public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom) { // 为add-in 设置代码 SetApplicationFields(application); // 更多代码 } |
添加命令条
通过应用程序的CommandBars对象集合给应用程序添加新的命令条。下面的方法给CommandBars集合添加一个命令条。当你调用该方法时,需要给它传递一个正在运行的Office应用程序实例的引用。在上面一段中,Word应用程序引用保持在类字段wordApp中。Missing变量的使用在段"C# Add-in中的可选参数"中解释。
在应用程序中放置一个命令条
1、给Connect类添加下面的方法。
' Visual Basic Private Function AddWordToolbar(ByVal word As Word.Application, _ ByVal toolbarName As String) As Microsoft.Office.Core.CommandBar Dim toolBar As Microsoft.Office.Core.CommandBar = Nothing Try ' 为add-in建立一个命令条 toolBar = CType(word.CommandBars.Add(toolbarName, _ Microsoft.Office.Core.MsoBarPosition.msoBarTop, , True), _ Microsoft.Office.Core.CommandBar) toolBar.Visible = True Return toolBar Catch ' 此处添加异常处理 Return Nothing End Try End Function // C# private Microsoft.Office.Core.CommandBar AddWordToolbar( Word.Application word, string toolbarName) { Microsoft.Office.Core.CommandBar toolBar = null; try { //为add-in建立一个命令条 object missing = System.Reflection.Missing.Value; toolBar = (Microsoft.Office.Core.CommandBar) wordApp.CommandBars.Add(toolbarName, Microsoft.Office.Core.MsoBarPosition.msoBarTop, missing, true ); toolBar.Visible = true; return toolBar; } catch { //此处添加异常处理 return null; } } |
2、给OnConnection方法添加下面的代码来建立add-in载入时的工具条。
' Visual Basic Dim toolbar As Microsoft.Office.Core.CommandBar = Nothing If Not wordApp Is Nothing Then toolbar = AddWordToolbar(wordApp, "Some useful toolbar.") End If // C# Microsoft.Office.Core.CommandBar toolBar = null; if (wordApp != null) { toolBar = AddWordToolbar(wordApp, "Some useful toolbar."); } |
如果你是使用Visual Basic并且Option Strict设置为Off,能使用迟绑定属性并跳过把OnConnection方法中的application引用转换为正确应用程序类型的步骤。Word和Excel都有CommandBars属性,你能通过迟绑定直接从application引用中使用它。
调试Add-in
你能在开发环境中建立、安装、运行和调试add-in。为了实现这些功能,需要对add-in项目的一些默认设置作一些修改。
为add-in项目调整默认设置
1、在解决方法管理器中右击该add-in项目,选择"属性"。
2、在"属性"对话框的左侧,选择"配置属性",接着选择它下面的"调试"。把Debug Mode设置为Program,把Start Application设置为Word可执行文件的目录。默认的启动程序是Visual Studio .NET,但是该add-in不在Visual Studio .NET中运行。
3、建立该add-in项目并安装项目。
4、在解决方案管理器中右击安装项目,选择"安装"。
5、按F5启动Word并载入该add-in。如果你的操作代码只有本文给定的代码,工具条会显示在Word中,但是它上面没有按钮。
代码产生的异常将被Office应用程序截取并且不会自动返回调试器。为了改善调试的行为,你可以在异常处中断或者大范围使用try/catch块。要注意如果你在所有异常处中断,调试器可能在与应用程序不相关的异常处中断。
在异常处中断
1、从"调试"菜单中选择"异常"。
2、选择"通用语言运行时异常"节点。
3、在"当出现异常时"组中选择"中断进入调试器"。
Office使失败的add-in不可用,Office把所有可管理add-in解释成相同的,因为它们共享mscoree.dll。因此当add-in失败时,需要卸载失败的add-in。
给命令条添加按钮
一旦建立了工具条就能给它添加按钮和其它控件。对于每个添加给工具条的按钮,你需要给Connect类添加一个引用变量和一个处理给按钮点击事件的方法。把按钮引用作为类的成员实现确保了该按钮的生命周期与应用程序的相同,并且载add-in还在载入、按钮仍然需要时不会被无用单元收集程序例行测试破坏。
对于每个新按钮,你可以指定一个FaceID,它是一个整数,映射到Office库的某个图标。随Office分发、可以被按钮使用的图标数以百计。
因为可能会给工具条增加几个按钮,给Connect类添加一个方法是值得的,该方法实例化按钮、把它添加到工具条,并把它与点击事件处理程序关联。
下面的代码使用了添加到命令条按钮点击事件的委托。你可能使用OnAction属性设置按钮的事件处理程序。
给命令条添加按钮和建立事件处理程序
1、使用Clipboard对象添加一个System.Windows.Forms引用。
2、为建立按钮添加下面的代码。该方法建立和返回了新按钮的引用。它点击事件的设置了标题、图标(FaceId)和事件处理程序。
' Visual Basic Private Function MakeANewButton(ByVal commandBar As _ Microsoft.Office.Core.CommandBar, ByVal caption As String, _ ByVal faceID As Integer, ByVal clickHandler As _ Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler) _ As Microsoft.Office.Core.CommandBarButton Try Dim newButton As Microsoft.Office.Core.CommandBarButton newButton = CType(commandBar.Controls.Add( _ Microsoft.Office.Core.MsoControlType.msoControlButton), _ Microsoft.Office.Core.CommandBarButton) newButton.Caption = caption newButton.FaceId = faceID AddHandler newButton.Click, clickHandler Return newButton Catch ex As System.Exception ' 添加处理异常的代码 Return Nothing End Try End Function // C# private Microsoft.Office.Core.CommandBarButton MakeANewButton( Microsoft.Office.Core.CommandBar commandBar, string caption, int faceID, Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler clickHandler ) { object missing = System.Reflection.Missing.Value; try { Microsoft.Office.Core.CommandBarButton newButton; newButton = (Microsoft.Office.Core.CommandBarButton) commandBar.Controls.Add( Microsoft.Office.Core.MsoControlType.msoControlButton, missing, missing, missing, missing); newButton.Caption = caption; newButton.FaceId = faceID; newButton.Click += clickHandler; return newButton; } catch (System.Exception ex) { //添加处理异常的代码 return null; } } |
3、为按钮引用给Connect类添加下面的声明。
' Visual Basic Dim insertText As Microsoft.Office.Core.CommandBarButton Dim styleText As Microsoft.Office.Core.CommandBarButton // C# Microsoft.Office.Core.CommandBarButton insertText; Microsoft.Office.Core.CommandBarButton styleText; |
4、给Connect类添加下面的方法。它们将作为按钮的点击事件的事件处理程序。这段代码使用了类字段wordApp和 excelApp。
' Visual Basic Public Sub insertText_Click(ByVal barButton As _ Microsoft.Office.Core.CommandBarButton, ByRef someBool As Boolean) Dim text As String = "" Dim data As System.Windows.Forms.IDataObject = _ System.Windows.Forms.Clipboard.GetDataObject() If data.GetDataPresent(System.Windows.Forms.DataFormats.Text) Then text = data.GetData( _ System.Windows.Forms.DataFormats.Text).ToString() If (Not wordApp Is Nothing) Then Me.wordApp.ActiveWindow.Selection.InsertBefore(text) ElseIf (Not excelApp Is Nothing) Then Me.excelApp.ActiveCell.Value = text End If End If End Sub Public Sub styleText_Click(ByVal barButton As _ Microsoft.Office.Core.CommandBarButton, ByRef someBool As Boolean) Dim code As Object = "Code" If (Not wordApp Is Nothing) Then Me.wordApp.ActiveWindow.Selection.Style = code ElseIf (Not excelApp Is Nothing) Then Me.excelApp.ActiveCell.Style = code End If End Sub // C# public void insertText_Click(Microsoft.Office.Core.CommandBarButton barButton, ref bool someBool) { string text = ""; System.Windows.Forms.IDataObject data = System.Windows.Forms.Clipboard.GetDataObject(); if (data.GetDataPresent(System.Windows.Forms.DataFormats.Text)) { text = data.GetData(System.Windows.Forms.DataFormats.Text). ToString(); if (wordApp != null) { this.wordApp.ActiveWindow.Selection.InsertBefore(text); } else if (excelApp != null) { this.excelApp.ActiveCell.Value2 = text; } } } public void styleText_Click(Microsoft.Office.Core.CommandBarButton barButton, ref bool someBool) { object code = "Code"; if (wordApp != null) { this.wordApp.ActiveWindow.Selection.set_Style(ref code); } else if (excelApp != null) { this.excelApp.ActiveCell.Style = code; } } |
5、给OnConnection方法添加下面的代码来建立add-in载入时的按钮。为了调用这个方法,必须有一个到包含按钮的命令条的引用。在例子中,上面的AddWordToolbar方法用于建立保持按钮工具条。
' Visual Basic ' 建立工具条 Dim toolbar As Microsoft.Office.Core.CommandBar = Nothing If Not wordApp Is Nothing Then toolbar = AddWordToolbar(wordApp, "Some useful toolbar.") End If ' 建立按钮添加文本 insertText = MakeANewButton(toolbar, "Insert text", 1044, _ AddressOf insertText_Click) ' 建立按钮改变选择的文本 styleText = MakeANewButton(toolbar, "Style text", 1081, _ AddressOf styleText_Click) // C# //建立工具条 Microsoft.Office.Core.CommandBar toolBar = null; if (wordApp != null) { toolBar = AddWordToolbar(wordApp, "Some useful toolbar."); } //建立按钮添加文本 insertText = MakeANewButton(toolBar, "Insert text", 1044, new Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler (insertText_Click)); //建立按钮改变选择的文本 styleText = MakeANewButton(toolBar, "Style text", 1081, new Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler (styleText_Click)); |
用C#获得或设置对象模型属性
在前面一段中,Visual Basic中的样式使用了ActiveCell的Style属性设置。在C#代码中样式使用set_Style方法设置。当需要改变时,Intellisense会建议使用正确的方法。该方法有一个引用的System.Object参数。System.Object类型可以保持任意类型的数据。有些对象模型属性可以使用System.Type.InvokeMember方法访问。
给Add-in添加Windows窗体
给add-in添加Windows传统与给普通.NET应用程序没有什么区别。Windows应用程序所需要的相应的项目引用都随着新窗体一起添加进来了。
窗体与Office的交互操作依赖于窗体是否为非模态的(modeless)。非模态窗体不能直接与Office对象模型交互。作为代替,你必须设计应用程序使非模态窗体给调用代码返回信息。接着调用代码可以与对象模型交互。通常模态窗体能够与Office对象某些交互。
给应用程序添加输入窗体
1、右击add-in项目,点击"添加",选择"添加Windows窗体"。
2、输入StyleSelection作为窗体的名字。
3、给新窗体添加一个ListBox控件,使用项集合编辑器添加三个项(Text、Code和Link)。把ListBox控件的Modifiers属性设置为Public。
4、添加两个按钮。按下表设置属性。
按钮 属性 值
Button1 Name OK
DialogResult OK
Text OK
Button2 Name Cancel
DialogResult Cancel
Text Cancel
5、给Connect类添加下面的方法。该方法建立窗体的一个实例,显示它,检查DialogResult并相应改变当前选择的颜色。
' Visual Basic Public Sub changeStyle_Click(ByVal barButton As _ Microsoft.Office.Core.CommandBarButton, ByRef someBool As Boolean) Dim selectionForm As New StyleSelection() Dim newStyle As Object = "" If selectionForm.ShowDialog() = _ System.Windows.Forms.DialogResult.OK Then newStyle = selectionForm.ListBox1.Text End If If Not wordApp Is Nothing Then Me.wordApp.ActiveWindow.Selection.Style = newStyle ElseIf Not excelApp Is Nothing Then Me.excelApp.ActiveCell.Style = newStyle End If End Sub // C# public void changeStyle_Click(Microsoft.Office.Core.CommandBarButton barButton, ref bool someBool) { StyleSelection selectionForm = new StyleSelection(); object newStyle = ""; if (selectionForm.ShowDialog() == System.Windows.Forms.DialogResult.OK) { newStyle = selectionForm.listBox1.Text; } if (wordApp != null) { this.wordApp.ActiveWindow.Selection.set_Style(ref newStyle); } else if (excelApp != null) { this.excelApp.ActiveCell.Style = newStyle; } } |
6、建立一个类字段来保持某个按钮的引用。点击这个按钮将显示StyleSelection窗体。
</ccid_nobr> ' Visual Basic Dim changeStyle As Microsoft.Office.Core.CommandBarButton // C# Microsoft.Office.Core.CommandBarButton changeStyle; |
' Visual Basic changeStyle = Me.MakeANewButton(toolbar, "Select style", 1082, _ AddressOf changeStyle_Click) // C# changeStyle = this.MakeANewButton(toolBar, "Select style", 1082, new Microsoft.Office.Core._CommandBarButtonEvents_ClickEventHandler (changeStyle_Click)); |
为Office应用程序查找文档
Office对象模型的文档是Office应用程序的一部分,而不是Visual Studio的一部分。例子是为了访问Word的文档,启动Word,指向工具菜单的"宏"(Macro)命令,接着点击Visual Basic编辑器。在编辑器中使用"帮助"菜单获得对象模型帮助。
C# Add-in中的可选参数
如果你查看Word对象模型的文档,会发现在很多方法的参数列表中有可选参数。如果你在Visual Basic .NET中开发应用程序,可以在调用试不管这些参数。如果是使用Visual C#,必须发送一个值表明缺少值。你可以简单地传递null,因为方法要求使用引用传递值。在.NET框架组件中,该值是System.Reflection.Missing.Value。它的声明如下:
// C# object missing = System.Reflection.Missing.Value; |
安全问题
你可以结合COM add-in填隙片(shim),关闭"Trust installed Add-Ins"选项使add-in运行在高安全模式下。否则将使Office应用程序运行在较低安全层次。
结论
使用Visual Studio .NET建立Office add-in允许你使用Office的丰富的对象模型和.NET框架组件的新编程体系。本文的技巧可能需要根据特定情况轻微改变。