【问题标题】:Side-By-Side COM Interop with C# and VBA与 C# 和 VBA 的并行 COM 互操作
【发布时间】:2013-05-23 04:12:01
【问题描述】:

我不是在谈论从 C# 调用 VBA COM……反过来!

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

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

或者,还有其他方法可以在 Access 中使用未注册的 C# 库吗?

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

【问题讨论】:

    标签: c# vba com-interop side-by-side


    【解决方案1】:

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

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

    以下是如何在您的 VBA 项目中使用 C# dll 的示例。由this答案稍作修改。

    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 格式存储在表格或电子表格中,然后将它们转换并导出为二进制文件。

    通过创建与 DLL 一起使用的类型库(通过使用 tlbexp),并在我的 VBA 项目中添加对 TLB 的引用,我能够使早期绑定(以及因此 Microsoft IntelliSense)工作,但它确实很复杂有点重要,因为它需要您的 VBA 应用程序知道 DLL 和 TLB 文件在哪里(并且还需要有人确保它们在那里)。

    【讨论】:

      【解决方案2】:

      您不必拥有该 exe 即可使用 SxS,SxS 是 Activation Context 的另一种说法。 如果您可以将相关的 win32 调用导入 vba(并且可以),那么您可以使用 activation context api 加载您的清单文件。

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

      【讨论】:

      • 我研究过使用该 API。具有讽刺意味的是,微软创建了一个包来避免需要注册本身的注册,并留下了我之前遇到的相同问题 - 如何在我的客户机器上获取它?尽管 Microsoft.Windows.Actctx 可用于 Windows 2K3+,但它仅包含在服务器安装中。还有另一个 SO 问题在这里抱怨:stackoverflow.com/questions/979567/…。 MSDN 在这里支持它:msdn.microsoft.com/en-us/library/aa375644(VS.85).aspx.
      • 据我所知,Activation Context API 是 Kernel32.lib 的一部分,这意味着您不必安装任何东西,它包含在任何支持 SxS 的操作系统中WinXP SP2 及更高版本。我自己在 WinXP SP3 上完成了它,它无需特殊安装即可工作。我不了解 Microsoft.Windows.Actctx,但我 100% 确定您可以通过从 Kernel32.lib 导入相关函数并直接调用它们来直接调用 API。就像在这个示例代码中展示的一样 mazecomputer.com/sxs/help/sxsapi3.htm
      • 哦,我明白了。我在网上看到的所有在 VBA 中执行此操作的示例都使用 Actctx 对象而不是 API,这是我最初得出结论认为它无法在代码中完成的唯一原因。显然,它以两种方式实现(并称为相同的东西)只是为了让我感到困惑。启动和运行它应该不会有太多麻烦——它应该是比破解 IL 更稳定的解决方案——所以当我到达那里时,我会移动接受的解决方案标志。感谢您的帮助!
      • 乐于助人。我知道这很令人困惑,我知道这一点的唯一原因是因为我现在正在做几乎相同的事情,而且在获得术语之前我必须深入挖掘。
      【解决方案3】:

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

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

      【讨论】:

      • 这非常聪明,而且确实很有意义。在我之前搜索有关破解 IL 以强制 C# 导出方法时,我没有找到任何东西。我得到了那个部分的工作,我认为让它成为一个返回对象的入口点应该不会太困难。感谢您的建议!
      【解决方案4】:

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

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

      【讨论】:

      • 我对 C# DLL 可以在未注册的情况下使用的印象来自这里:msdn.microsoft.com/en-us/library/ms973915.aspx 那里有一个 C# .NET 服务器和一个非 .NET 客户端。我相信这基本上等同于我想要做的事情,除了客户端是 VB6 可执行文件而不是 VBA 应用程序这一事实。还有什么我想念的吗?谢谢!
      • 您可能会卡在需要为客户端创建清单文件的部分,因为 VBA 不是您可以为其生成的独立程序。清单看起来很简单,但我不能确定如何正确关联它。也许您可以让 VBA 执行一个独立的客户端来满足您的需求?
      猜你喜欢
      • 2011-07-02
      • 1970-01-01
      • 2014-09-03
      • 2011-05-12
      • 1970-01-01
      • 2010-12-14
      • 2012-06-18
      • 2012-03-24
      • 2011-11-18
      相关资源
      最近更新 更多