使用VB.NET构建VBA IDE的Add-In

13

我曾经在其他地方问过这个问题,但从来没有找到人知道如何使用VB.NET为VBA IDE构建插件。这是否是可能的?有人可以给我提供一个示例吗?

6个回答

18

如果需要使用IDTExtensibility2接口编写COM Add-in,可以从新项目中选择共享Add-in项目模板。

编辑

否则,如果要从头创建此Add-in,则需要执行以下操作:

  1. 创建一个新项目类库
  2. 添加对“Extensibility”的引用,它应该在列表中。您可能需要为您的Office版本下载PIAs。(也许还需要VSTO,但我不确定)
  3. 再次添加对“Microsoft.Vbe.Interop”的引用,应与PIAs一起提供。
  4. 在属性选项卡中勾选“注册Com互操作性”复选框。
  5. 可选项:在调试设置选项卡中将启动项更改为外部程序,并输入Excel.exe的路径(如果此程序是针对Excel的),以允许调试该项目。
  6. 可选项:在命令选项中添加一个条目到一个工作表或Word文档,以使用启动宏显示Add-in对话框,对于开发而言,这样做可以简化调试体验。例如:"C:\vbe.xlsm"。
  7. 可选项:同时将启动路径设置为工作表目录,例如:“C:\”。
  8. 实现“Extensibility”程序集中找到的“IDTExtensibility2”接口。
  9. 将此类命名为“Connect”(这只是个人偏好)
  10. 用以下属性注释类

[ComVisible(true), Guid("YourGeneratedGuid"), ProgId("YourAddinName.Connect")]

这是一个起点实现,首先将“YourAddinName”替换为您的AppName,并为“YourGeneratedGuid”创建一个GUID。您需要将Add-in注册到正确的注册表位置,请查看下面的注册表键以了解大致情况,并在注册表键中替换一些变量。

Imports System
Imports System.Drawing
Imports System.Linq
Imports System.Runtime.InteropServices
Imports Extensibility
Imports Microsoft.Vbe.Interop

Namespace VBEAddin


''' <summary>
''' The object for implementing an Add-in.
''' </summary>
''' <seealso class='IDTExtensibility2' />
<Guid("YourGeneratedGuid"), ProgId("YourAddinName.Connect")> _ 
Public Class Connect
    Implements IDTExtensibility2
    Private _application As VBE 'Interop VBE application object


    #Region "IDTExtensibility2 Members"

    ''' <summary>
    ''' Implements the OnConnection method of the IDTExtensibility2 interface.
    ''' Receives notification that the Add-in is being loaded.
    ''' </summary>
    ''' <param term='application'>
    ''' Root object of the host application.
    ''' </param>
    ''' <param term='connectMode'>
    ''' Describes how the Add-in is being loaded.
    ''' </param>
    ''' <param term='addInInst'>
    ''' Object representing this Add-in.
    ''' </param>
    ''' <seealso class='IDTExtensibility2' />
    Public Sub OnConnection(ByVal application As Object, ByVal connectMode As ext_ConnectMode, ByVal addInInst As Object, ByRef [custom] As Array)
    _application = CType(Application,VBE)
    End Sub

    Private Sub onReferenceItemAdded(ByVal reference As Reference)
        'TODO: Map types found in assembly using reference.
    End Sub

    Private Sub onReferenceItemRemoved(ByVal reference As Reference)
        'TODO: Remove types found in assembly using reference.
    End Sub


    Private Sub BootAddin()
        'Detect change in active window. 
    End Sub

    ''' <summary>
    ''' Implements the OnDisconnection method of the IDTExtensibility2 interface.
    ''' Receives notification that the Add-in is being unloaded.
    ''' </summary>
    ''' <param term='disconnectMode'>
    ''' Describes how the Add-in is being unloaded.
    ''' </param>
    ''' <param term='custom'>
    ''' Array of parameters that are host application specific.
    ''' </param>
    ''' <seealso class='IDTExtensibility2' />
    Public Sub OnDisconnection(ByVal disconnectMode As ext_DisconnectMode, ByRef [custom] As Array)
    End Sub

    ''' <summary>
    ''' Implements the OnAddInsUpdate method of the IDTExtensibility2 interface.
    ''' Receives notification that the collection of Add-ins has changed.
    ''' </summary>
    ''' <param term='custom'>
    ''' Array of parameters that are host application specific.
    ''' </param>
    ''' <seealso class='IDTExtensibility2' />
    Public Sub OnAddInsUpdate(ByRef [custom] As Array)
    End Sub

    ''' <summary>
    ''' Implements the OnStartupComplete method of the IDTExtensibility2 interface.
    ''' Receives notification that the host application has completed loading.
    ''' </summary>
    ''' <param term='custom'>
    ''' Array of parameters that are host application specific.
    ''' </param>
    ''' <seealso class='IDTExtensibility2' />
    Public Sub OnStartupComplete(ByRef [custom] As Array)
        'Boot dispatcher

    End Sub


    ''' <summary>
    ''' Implements the OnBeginShutdown method of the IDTExtensibility2 interface.
    ''' Receives notification that the host application is being unloaded.
    ''' </summary>
    ''' <param term='custom'>
    ''' Array of parameters that are host application specific.
    ''' </param>
    ''' <seealso class='IDTExtensibility2' />
    Public Sub OnBeginShutdown(ByRef [custom] As Array)
    End Sub

    #End Region
End Class
End Namespace

这是注册Addin的注册表.key脚本,注意您需要更改一些设置才能正确注册它。

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\VBA\VBE\6.0\Addins\YourAddinName.Connect]
"CommandLineSafe"=dword:00000000
"Description"="Description for your new addin"
"LoadBehavior"=dword:00000000
"FriendlyName"="YourAddinName"


[HKEY_CLASSES_ROOT\CLSID\{YourGeneratedGuid}]
@="YourAddinName.Connect"

[HKEY_CLASSES_ROOT\CLSID\{YourGeneratedGuid}\Implemented Categories]

[HKEY_CLASSES_ROOT\CLSID\{YourGeneratedGuid}\InprocServer32]
@="mscoree.dll"
"ThreadingModel"="Both"
"Class"="YourAddinName.Connect"
"Assembly"="YourAssemblyNameFullTypeName"
"RuntimeVersion"="v2.0.50727"
"CodeBase"="file:///PathToAssembly"

[HKEY_CLASSES_ROOT\CLSID\{YourGeneratedGuid}\ProgId]
@="YourAddinName.Connect"

注意: "YourGeneratedGuid" 标记必须包含大括号 {},并且与上面的 "attrib" 中的 GUID 相同;标记 "YourAssemblyNameFullTypeName" 必须是程序集的全名;标记 "YourAddinName.Connect" 必须与上面的 "attrib" 中设置的 ProgId 相同。

另外提示:

还发现这个有用,可能会为您节省几个小时的谷歌搜索。

'HKEY_CURRENT_USER\Software\Microsoft\VBA\6.0\Common
'FontFace=Courier New (STRING - Default if missing)
'FontHeight=10 (DWORD - Default if missing)                

嗨Ori,我面临的问题是我正在使用VB.Net的Express版本。 Express版本的限制之一是模板集减少了。我想象你仍然可以做到这一点,只需从头开始创建一个。有任何建议从哪里开始吗?我查看了MZ-Tools资源,但他们的信息不适用于来自.Net的VBA IDE。这就是我无论到哪里都遇到的问题。我能找到的所有信息都是关于VB6的。 - Oorang
1
哇,这真的很多。为你的努力点赞。我需要时间来尝试一下,如果有效,我会接受的:) 谢谢:) - Oorang
嗨ORI,抱歉回复晚了。我在这方面非常新手,请多包涵。我开始尝试实现这些指令,但我遇到的第一个障碍是(使用2010年版的VB Express),没有“共享插件项目模板”可用(也不在在线集合中)。我知道它在完整版的VS中,所以我认为它只是缺少Express版本。您知道解决此问题的方法吗?抱歉让事情变得复杂了。 - Oorang

11

很遗憾,almog.ori的方法对我没有用。这是我为了帮助未来的人们而创建的版本:

  1. 创建一个名为“VBEAddIn”的C#或VB.NET类库项目。

    使用“项目”,“添加引用...”菜单,“浏览”选项卡,将以下Interop程序集添加为项目的引用。

  2. Extensibility (C:\Program Files\Microsoft Visual Studio 10.0\Visual Studio Tools for Office\PIA\Common\Extensibility.dll) - 如果它不在那里,请尝试 C:\Program Files (x86)\ ,如果你使用的是 x64 电脑。

  3. Microsoft.Office.Interop.Excel (C:\Program Files\Microsoft Visual Studio 10.0\Visual Studio Tools for Office\PIA\Office14\Microsoft.Office.Interop.Excel.dll)

  4. Microsoft.Vbe.Interop (C:\Program Files\Microsoft Visual Studio 10.0\Visual Studio Tools for Office\PIA\Office14\Microsoft.Vbe.Interop.dll)

  5. (可选) Microsoft.Vbe.Interop.Forms (C:\Program Files\Microsoft Visual Studio 10.0\Visual Studio Tools for Office\PIA\Office14\Microsoft.Vbe.Interop.Forms.dll)

向您的项目添加一个类,并使用以下代码:

VB.Net:

Imports Microsoft.Office.Interop
Imports Extensibility
Imports System.Windows.Forms
Imports System.Runtime.InteropServices
Imports Microsoft.Vbe.Interop

<ComVisible(True), Guid("3599862B-FF92-42DF-BB55-DBD37CC13565"), ProgId("VBEAddInVB.Net.Connect")> _
Public Class Connect
    Implements Extensibility.IDTExtensibility2

    Private _VBE As VBE
    Private _AddIn As AddIn

    Private Sub OnConnection(Application As Object, ConnectMode As Extensibility.ext_ConnectMode, _
       AddInInst As Object, ByRef custom As System.Array) Implements IDTExtensibility2.OnConnection
        Try
            _VBE = DirectCast(Application, VBE)
            _AddIn = DirectCast(AddInInst, AddIn)
            Select Case ConnectMode
                Case Extensibility.ext_ConnectMode.ext_cm_Startup
                Case Extensibility.ext_ConnectMode.ext_cm_AfterStartup
                    InitializeAddIn()
            End Select
        Catch ex As Exception
            MessageBox.Show(ex.ToString())
        End Try
    End Sub

    Private Sub OnDisconnection(RemoveMode As Extensibility.ext_DisconnectMode, _
       ByRef custom As System.Array) Implements IDTExtensibility2.OnDisconnection

    End Sub

    Private Sub OnStartupComplete(ByRef custom As System.Array) _
       Implements IDTExtensibility2.OnStartupComplete
        InitializeAddIn()
    End Sub

    Private Sub OnAddInsUpdate(ByRef custom As System.Array) Implements IDTExtensibility2.OnAddInsUpdate

    End Sub

    Private Sub OnBeginShutdown(ByRef custom As System.Array) Implements IDTExtensibility2.OnBeginShutdown

    End Sub

    Private Sub InitializeAddIn()
        MessageBox.Show(_AddIn.ProgId & " loaded in VBA editor version " & _VBE.Version)
    End Sub

End Class

C#:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Extensibility;
using Microsoft.Vbe.Interop;
using System.Windows.Forms;

namespace VBEAddin
{
    [ComVisible(true), Guid("3599862B-FF92-42DF-BB55-DBD37CC13565"), ProgId("VBEAddIn.Connect")]
    public class Connect : IDTExtensibility2
    {
        private VBE _VBE;
        private AddIn _AddIn;

        #region "IDTExtensibility2 Members"

        public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
        {
            try 
            {
                _VBE = (VBE)application;
                _AddIn = (AddIn)addInInst;

                switch (connectMode) 
                {
                    case Extensibility.ext_ConnectMode.ext_cm_Startup:
                        break;
                    case Extensibility.ext_ConnectMode.ext_cm_AfterStartup:
                        InitializeAddIn();

                        break;
                }
            }
            catch (Exception ex) 
            {
                MessageBox.Show(ex.ToString());
            }
        }

        private void onReferenceItemAdded(Reference reference)
        {
            //TODO: Map types found in assembly using reference.
        }

        private void onReferenceItemRemoved(Reference reference)
        {
            //TODO: Remove types found in assembly using reference.
        }

        public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
        {
        }

        public void OnAddInsUpdate(ref Array custom)
        {
        }

        public void OnStartupComplete(ref Array custom)
        {
              InitializeAddIn();
        }

        private void InitializeAddIn()
        {
            MessageBox.Show(_AddIn.ProgId + " loaded in VBA editor version " + _VBE.Version);
        }

        public void OnBeginShutdown(ref Array custom)
        {
        }

        #endregion
    }
}
在项目的“属性”窗口中:
  1. 在“应用程序”选项卡中,确保“程序集名称”和“根命名空间”均设置为“VBEAddIn”。

  2. 在“编译”选项卡中,确保“注册COM互操作”复选框已被选中。我们不会使用适当的regasm.exe工具手动注册程序集以进行COM互操作。但请注意,“注册COM互操作”复选框仅会将插件dll注册为32位COM库,而不是64位COM库。

  3. 在“编译”选项卡中,“高级编译选项”按钮上,确保“目标CPU”组合框设置为“AnyCPU”,这意味着程序集可以作为64位或32位执行,取决于加载它的.NET Framework。

  4. 在“签名”选项卡中,确保未选中“对程序集进行签名”。

接下来添加注册表键,请将下面的代码片段保存为带有.reg扩展名的ASCI文件,并双击该文件将值添加到注册表中。

重要提示:在执行reg文件之前,更改路径:“CodeBase”=“file:///C:\Dev\VBEAddIn\VBEAddIn\bin\Debug\VBEAddIn.dll”

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\VBA\VBE\6.0\Addins\VBEAddIn.Connect]
"CommandLineSafe"=dword:00000000
"Description"="Description for your new addin"
"LoadBehavior"=dword:00000000
"FriendlyName"="VBEAddIn"


[HKEY_CLASSES_ROOT\CLSID\{3599862B-FF92-42DF-BB55-DBD37CC13565}]
@="VBEAddIn.Connect"

[HKEY_CLASSES_ROOT\CLSID\{3599862B-FF92-42DF-BB55-DBD37CC13565}\Implemented Categories]

[HKEY_CLASSES_ROOT\CLSID\{3599862B-FF92-42DF-BB55-DBD37CC13565}\InprocServer32]
@="mscoree.dll"
"ThreadingModel"="Both"
"Class"="VBEAddIn.Connect"
"Assembly"="VBEAddIn"
"RuntimeVersion"="v2.0.50727"
"CodeBase"="file:///C:\Dev\VBEAddIn\VBEAddIn\bin\Debug\VBEAddIn.dll"

[HKEY_CLASSES_ROOT\CLSID\{3599862B-FF92-42DF-BB55-DBD37CC13565}\ProgId]
@="VBEAddIn.Connect"
  1. 在Visual Studio中构建VBE Add-in,并打开Excel。
  2. 打开VBA编辑器(Alt + F11)。
  3. 转到“附加组件”,“附加组件管理器...”菜单,检查附加组件是否正确注册。
  4. 加载该附加组件。您应该会看到消息框“VBEAddIn.Connect已在VBA编辑器中加载”。

如果出现以下错误:

enter image description here

'VBEAddIn'无法加载。

将其从可用的附加程序列表中删除?

那么很可能是您没有更改路径 "CodeBase"="file:///C:\Dev\VBEAddIn\VBEAddIn\bin\Debug\VBEAddIn.dll"。

并检查注册表中的CodeBase键(如果不存在,请添加带有CodeBase的字符串regkey):

enter image description here

然后关闭Office应用程序,再次从Visual Studio中构建VBE AddIn,打开Office(Excel,Outlook,Word等),Alt+F11,附加组件菜单>附加组件管理器并选择AddIn,选中“已加载/未加载”。

最后的技巧是解决此问题的方法:

如果以上仍然失败,请关闭Office应用程序,转到Visual Studio,项目属性>生成选项卡>选中COM互操作注册>构建解决方案,并打开Office Add In> Alt + F11> AddIns菜单> AddIn Manager并单击"已加载/未加载"


本答案使用了Carlo's Quintero (MZTools)的一些信息,经过了修改,参考:http://www.mztools.com/articles/2012/MZ2012013.aspx


1

我也发现这个参考资料对于从C#或VB.NET制作VBA DLL非常有帮助:

  1. 创建一个新的C#(或VB.Net)项目,并选择类库作为模板类型。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace SimpleCalc
    {
        public class Calc
        {
            private int numberOne = 0;
            private int numberTwo = 0;
    
            public void SetNumberOne(int number)
            {
                numberOne = number;
            }
    
            public void SetNumberTwo(int number)
            {
                numberTwo = number;
            }
    
            // Add two integers
            public int Add()
            {
                return numberOne + numberTwo;
            }
        }
    }
    
  2. 配置项目属性使其COM可见。

  3. 注册COM互操作性。
  4. 编译项目。
  5. 将类型库文件复制到Windows系统文件夹中。
  6. 从Access VBA编辑器引用类型库。

    Public Function test()
        Dim lngResult As Long
    
        Dim objCalc As SimpleCalc.Calc
        Set objCalc = New SimpleCalc.Calc
    
        objCalc.SetNumberOne (3)
        objCalc.SetNumberTwo (6)
    
        lngResult = objCalc.Add()
    
    End Function
    

GeeksEngine.com提供


0
我想你可以从你的VBA代码中调用一个.NET DLL(我自己从未尝试过这样做)。只需创建一个VB类库项目并创建一个DLL以在您的VBA中使用。
经过快速搜索,看起来您需要在项目属性->构建下设置“注册Com互操作”= True,但像我说的那样,我以前从未尝试过这个。

1
我认为他正在寻找一个用于开发环境本身的插件。 - almog.ori

0

还要注意项目的 GUID(在 C# 的 AssemblyInfo.cs 文件中)与“Connect”类的 GUID 不同。

如果 GUID 相同,则在检查时会导致“无法转换为类型库”的错误:项目属性 > 生成选项卡 > 注册 COM 互操作。


0
我完全同意Jeremy Thompson上面的回答。然而,我花了几个小时试图让示例VBEAddin工作。直到我注意到在Connect类代码中,ProgID属性是“VBEAddInVB.Net.Connect”,但是用于创建.reg文件的注册表文本中,所有对程序名称的引用都是“VBEAddIn.Connect”。所以我尝试将Connect类中的ProgId属性更改为“VBEAddIn.Connect”,重新构建它,然后它就可以工作了!我认为名称必须保持一致。希望这能节省其他人的时间。

这并没有回答问题。一旦你拥有足够的声望,你就可以评论任何帖子;相反,提供不需要提问者澄清的答案。- 来自审查 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接