7

我不是在谈论从 C# 调用 VBA COM ......相反!

我想做的是在 MS Access 中使用 VBA 调用 C# 库而不注册 DLL。我一直在玩并排互操作一段时间但没有成功,我终于意识到 mdb.manifest 可能不是 exe.manifest 的可接受替代品(可能很明显,我知道,但我试图保持乐观)。

我的问题:是否可以让 VBA 加载并排 COM 组件?

或者,是否有另一种方法可以在 Access 中使用未注册的 C# 库?

(在你问之前,我的理由是:我绝对不会被授予访问我客户的 Windows 注册表的权限——这就是为什么它首先是用 Access 编写的。而且,我需要在一个C# 应用程序很快,而不是做两次)。

4

4 回答 4

12

添加到已经存在的答案:使用.NET 4.0,在您的 VBA 项目中使用 C# dll 实际上非常简单,而无需注册 COM。

编辑:我刚刚尝试了这个mscorlib.tlb和- 加载在 3.5mscoree.tlbC:\windows\Microsoft.NET\Framework\v2.0.50727编译的程序集 - 它工作得很好。所以显然你不需要.NET 4.0。

下面是如何在 VBA 项目中使用 C# dll 的示例。对此答案略有修改。

1)添加对以下类型库的引用您的 VBA 项目(工具->引用):

C:\windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb
C:\windows\Microsoft.NET\Framework\v4.0.30319\mscoree.tlb

(如果您运行的是 64 位 Office,请使用 Framework64 文件夹)

2) 在您的 C# 项目中,确保将[ComVisible(true)]属性添加到您的类中:

using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace VB6FuncLib
{
    [ComVisible(true)]
    public class VB6FuncLib
    {
        public VB6FuncLib()
        { }
        public void test()
        {
            MessageBox.Show("Test Successful");
        }
    }
}

无需选中“注册 COM 互操作”选项。这仅用于构建标准 COM 对象。您也不必检查“使程序集 COM 可见”,除非您希望整个程序集可见(这也将消除对COMVisible属性的需要)。

3) 在您的 VBA 代码中,使用以下代码添加一个新模块:

Sub Test()
    Dim Host As mscoree.CorRuntimeHost
    Set Host = New CorRuntimeHost
    Host.Start
    Dim Unk As IUnknown
    Host.GetDefaultDomain Unk
    Dim AppDomain As AppDomain
    Set AppDomain = Unk
    Dim ObjHandle As ObjectHandle
    Set FS = CreateObject("Scripting.FileSystemObject")
    Path = FS.GetParentFolderName(CurrentDb().Name)
    Set ObjHandle = AppDomain.CreateInstanceFrom(Path & "\VB6 Function Library.dll", "VB6FuncLib.VB6FuncLib")
    Dim ObjInstance As Object
    Set ObjInstance = ObjHandle.Unwrap
    ObjInstance.test
    Host.Stop
End Sub

4) 将 DLL 复制到与您的 Office 项目相同的文件夹中,然后在 VBA 中运行 Test() 子程序。

笔记:

应该注意的是,这种技术的一个限制是,如果 .DLL 存储在远程网络共享上,它将无法工作。一种简单的解决方案是将其复制到正在使用它的每台 PC 上的同一本地文件夹中。另一种解决方案是将二进制文件包含在您的 Access 应用程序/VBA 项目中,并让 MS-Access 导出它们。可以实现的一种方法是将它们存储在 Base64 中的表格或电子表格中,然后将它们转换并导出为二进制文件。

I was able to get early binding (and therefore Microsoft IntelliSense) to work by creating a type library to go with the DLL (by using tlbexp), and adding a reference to the TLB in my VBA project, but it does complicate matters a bit because it requires your VBA app to know where both the DLL and the TLB files are (and also requires someone to make sure they are there).

于 2012-11-11T17:59:23.110 回答
3

您不必拥有 exe 即可使用 SxS,SxS 是Activation Context的另一个词。如果您可以将相关的 win32 调用导入 vba(并且可以),那么您可以使用激活上下文 api来加载清单文件。

更多关于这个主题和一些例子可以在这里找到。

于 2010-01-14T19:51:37.290 回答
1

问题是要使用 SxS,您需要拥有 exe 来设置配置以加载 SxS 程序集。您没有“拥有”访问权限,虽然您可以放入正确的配置以使其加载您的 .NET COM 内容而无需注册,但这不是一个“好公民”的举动。

如果您对 shimming 感到棘手,您可以设置一个非托管的 DLL(或带有 dllexport 的被黑 C# 类库,例如,参见这个),其导出将加载 .NET 框架,创建一个 COMVisible DispInterface 托管实例键入并返回它(该方法应返回 IDispatch)。然后将 VBA 声明写入您的 DLL 导出函数(声明为返回对象)。如果这没有意义,你可能不应该尝试它...... :) 我以前在类似的情况下做过这个,它确实有效,但我没有样本可以指向你。

于 2009-12-17T02:55:58.550 回答
0

C# 库不是常规的 DLL。它们更类似于 COM 库,在使用前需要注册(就像 ActiveX 控件一样);尤其是从非 .NET 代码调用时。

(当然,除非事情发生了变化……)

于 2009-12-14T20:24:34.813 回答