首页 > 解决方案 > 使用 VSTO 的 Microsoft Access 加载项

问题描述

我正在尝试扩展 MS Access 的功能。我希望用户能够从 Access 应用程序中触发此功能,最好是通过单击我介绍的按钮。我希望能够使用 C# 实现此功能。

如果我的目标是 MS Word、Excel、Outlook、PowerPoint、Visio、InfoPath 或 Project 中的任何一个,那么 Visual Studio Tools for Office(参见此处)将是理想的选择。然而,Access 要么从未(正式)成为该计划的一部分,要么在很久以前就不再得到它的官方支持例如,有一家名为 Add-In Express 的公司似乎支持带有 Access 的 VSTO ,但是许可证非常昂贵,如果可以直接完成,我宁愿不涉及第三方软件。有一篇 2008 年的 MS 博客文章,其中包含利用“VSTO 加载项项目在很大程度上与主机无关的性质”并将 Word 加载项转换为 Access 加载项的hack 。这有一个警告:

但是请注意,我不鼓励人们在生产中使用这种方法——我们没有测试过这种行为,并且明确不以任何方式支持它。我所做的是探索如何将 VSTO 设计为最佳地与主机无关,以便插件模型尽可能灵活 - 不会达到旧的“共享”插件提供的松散类型的极端模型。

这种方法是针对最近的 SO question 提出的,并且显然被提问者成功使用。虽然我担心缺乏官方支持,但这对于原型来说可能就足够了,我已经尝试使用它。

在没有任何问题的情况下执行步骤 1 到 8 后,我点击 Debug 并且 MS Access 启动,然后抛出以下错误对话框:

Microsoft Office Customization Installer
There was an error during installation.

Downloading file:///C:/Temp/MyAddIn/bin/Debug/MyAddIn.vsto did not succeed.

Details:

************** Exception Text **************
System.Deployment.Application.DeploymentDownloadException: Downloading 
file:///C:/Temp/MyAddIn/bin/Debug/MyAddIn.vsto did not succeed. ---> 
System.Net.WebException: Could not find a part of the path 
'C:\Temp\MyAddIn\bin\Debug\MyAddIn.vsto'. ---> System.Net.WebException: 
Could not find a part of the path 'C:\Temp\MyAddIn\bin\Debug\MyAddIn.vsto'. 
---> System.IO.DirectoryNotFoundException: Could not find a part of the path 
'C:\Temp\MyAddIn\bin\Debug\MyAddIn.vsto'.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess 
access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, 
FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean 
bFromProxy, Boolean useLongPath, Boolean checkHost)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess 
access, FileShare share, Int32 bufferSize, FileOptions options, String 
msgPath, Boolean bFromProxy)
   at System.Net.FileWebStream..ctor(FileWebRequest request, String path, 
FileMode mode, FileAccess access, FileShare sharing, Int32 length, Boolean 
async)
   at System.Net.FileWebResponse..ctor(FileWebRequest request, Uri uri, 
FileAccess access, Boolean asyncHint)
   --- End of inner exception stack trace ---
   at System.Net.FileWebResponse..ctor(FileWebRequest request, Uri uri, 
FileAccess access, Boolean asyncHint)
   at System.Net.FileWebRequest.GetResponseCallback(Object state)
   --- End of inner exception stack trace ---
   at System.Net.FileWebRequest.EndGetResponse(IAsyncResult asyncResult)
   at System.Net.FileWebRequest.GetResponse()
   at 
System.Deployment.Application.SystemNetDownloader.DownloadSingleFile
(DownloadQueueItem next)
--- End of inner exception stack trace --- 

谷歌搜索“vsto 下载文件没有成功”把我带到了这里,这似乎很相关:

问题是 Office 应用程序正在寻找部署清单 (.vsto) 和应用程序清单 (.dll.manifest) 并且无法找到它们。

我在我的机器上搜索了一个 vsto 文件扩展名,唯一找到的文件在我的 VS 解决方案文件夹中。所以我想也许博客方法中的第 6 步是错误的,最后一行应该替换为这个 vsto 文件的路径。然而,这似乎不是问题。

然后我发现这篇关于解决常见 VSTO 问题的 MSDN文章和常见错误 4 是匹配的。列出的“解决方案”是:

当 VSTO 解决方案尝试从域控制器获取证书信息(发布者名称和其他数据)并且超时时,通常会出现此问题。要解决此问题,请安装此修补程序:- KB 981574。

此链接此处是标题为的页面

当您尝试在安装了 .NET Framework 3.5 SP1 的计算机上启动 Excel 时,初始屏幕的打开时间比平时长

这似乎完全无关。这是一个断开的链接吗?我不确定如何进行。

标签: c#visual-studioms-accesspluginsoffice-addins

解决方案


我不认为 VSTO 工具真的值得麻烦,而且如果你创建一个“插件”,那么这样的插件将在 Access 启动时为所有 Access 应用程序加载,并且不限于你的一个应用程序。并且必须在 Office OFTEN 注册加载项会导致在 Access 中启动问题。因此,您的加载项必须加载,并加载任何和所有出于任何原因简单地启动 Access 的情况。

所有 VSTO 工具真正做的就是设置一个到 office 的 com 接口,在 .net 中构建一个“简单”类,然后在访问中从 VBA 按钮中使用它真的少了很多麻烦。

因此,一种简单的方法是“仅”使用 VBA/office 代码中的 .net 类。无论如何,搞乱 VSTO 确实没有多大帮助,当你让所有 VSTO 东西工作时,你只需在 .net 中编写一个简单的类就可以完成并完成。

一些提示:确保选中 .net“注册”中的复选框以进行 COM 互操作。请记住,此选项仅在您的开发计算机上的开发过程中为了您的方便而执行 regasm。

另一个选项(无论如何都是默认设置的!!!)在程序集区域中,您只需确保“使程序集 COM 可见)。

对于分发,您必须包含一个小批处理文件或使用安装程序。那个简单的批处理文件或安装程序必须在目标机器(非开发计算机)上执行“regasm”。

并确保您将项目强制为 x86(假设您使用的是 x32 的 office,这肯定是这种情况)。所以不要使用“任何”CPU,而是强制项目使用 x86 CPU。

除上述以外,仅此而已。

这是一个简单的.net 类。假设 .net 4.5 或更高版本,这允许您从 Access VBA 创建 zip 文件。

(您需要 system.IO.Compression 和 system.io.compression.Filesystem 作为 .net 项目中的引用。结果是在没有任何第三方工具的情况下从 Access 压缩文件。

因此.net 中的类是这样的:

Imports System.Runtime.InteropServices
Imports System.IO.Compression
Imports System.IO

<ClassInterface(ClassInterfaceType.AutoDual)>
Public Class AlbertCom1

Private m_Times2 As Integer

Public Sub MsgHello()

    MsgBox("Hello world", MsgBoxStyle.Information, "VB.net example")

End Sub

Public Sub MyZipper(strFileName As String, strZipFile As String)

    Using archive As ZipArchive = ZipFile.Open(strZipFile, ZipArchiveMode.Update)
        archive.CreateEntryFromFile(strFileName, Path.GetFileName(strFileName), CompressionLevel.Fastest)
    End Using

End Sub

Public Function GetConValue(strSetting As String) As String

    ' read a simple value from config file
    Return My.Settings(strSetting).ToString

End Function

Public Property Times2 As Integer
    Get
        Return m_Times2
    End Get
    Set(value As Integer)
        m_Times2 = value * 2
    End Set
End Property

End Class

所以上面的内容相当简单,简短。

在 Access VBA 中,在我们的按钮后面,我们可以使用以下代码:

从上面调用/使用 Hello 消息框方法:

Sub TestCOMHello()

  Dim mycom      As Object
  Set mycom = CreateObject("AlbertCom1.AlbertCom1")

  mycom.MsgHello

End Sub

注意上面的 LATE 绑定是如何工作的——这将在 VBA 中没有对对象的引用的情况下工作。(所以 createObject() 是必需的)。

但是,以下示例使用早期绑定,但都可以按照上述方式创建对象。

从 VBA 压缩文件:

Sub TestCOMZip()

  Dim strFromFile      As String
  Dim strToFile        As String

  Dim mycom      As New AlbertCom1.AlbertCom1

  strFromFile = "c:\test\data.txt"
  strToFile = "c:\test\data.zip"

  mycom.MyZipper strFromFile, strToFile


End Sub

还有一些提示:

您实际上不必在您的类中构建自定义界面,虽然许多人对使用 AutoDual 感到“皱眉”,但我认为这种方法很好。互联网上花费大量时间创建自定义界面的“示例”实际上只是世界贫困的借口。

最后一个重要提示:不要在你的类中公开任何不兼容的数据类型。如果您公开(意外或有意)任何与标准“com”对象不兼容的 .net 对象类型,那么您的 .net 类将编译得很好,但 Access 将无法正确查看或使用该对象。因此,在实际的上述类中将这些变量和例程保留(声明)为私有。(其他代码和部分无关紧要——我要说的只是一个类)。

因此,例如不要公开 .net long 数据类型。如果你坚持使用字符串、标准集合、数组等,那么你应该没问题。而且您实际上“可以”将不兼容的对象类型公开为 .net 中的“对象”。(Access 中的 Intel-sense 不会显示对象方法,但您仍然可以使用它们)。

虽然公共函数甚至公共变量对于您的对象方法来说是最简单的,但这里是按照“标准”方法使用 get/set 来了解如何创建类方法。

所以在.net中我们有:

Public Property Times2 As Integer
    Get
        Return m_Times2
    End Get
    Set(value As Integer)
        m_Times2 = value * 2
    End Set
End Property

在您的 VBA 代码中,我们有:

Sub TestTimes()

   Dim mycom     As New AlbertCom1.AlbertCom1

   mycom.Times2 = 40

   Debug.Print mycom.Times2

End Sub

output: 80

注意早期绑定,然后 Access VBA 编辑器将“吐出”类的属性和方法:

例如这个:

在此处输入图像描述

总而言之,使用 VSTO 通常是一个巨大的矫枉过正。只需构建一个简单的 .net 类来公开您需要从 VBA 使用/调用的内容,然后您就可以参加比赛了。另一个大好处是这个 COM 对象可以在 windows 脚本、VB6、FoxPro、Excel、Word、power-point 等中使用。换句话说,你不限于任何一个平台或只是访问来消费 + 使用你的简单类您公开为 COM 对象。在大多数情况下,我很难为 VSTO 提出理由。所以这个对象现在可以很容易地从任何办公应用程序(VBA 代码)中使用。


推荐阅读