【问题标题】:VBA - ActiveX Cant Create Object for .net dll with dependenciesVBA - ActiveX 无法为具有依赖关系的 .net dll 创建对象
【发布时间】:2019-06-02 14:03:45
【问题描述】:

我编写了一个 .Net 库,它封装了我的一些需要与遗留系统交互的业务逻辑。这个库的目的是公开一个 COM 接口,以便我可以使用 VBA 从 Office 应用程序调用它。

我已经完成了使用带有 /codebase /tlb 标志的 64 位 Regasm.exe 注册它所需的一切。它在我的 Office 应用程序中可见,甚至在智能感知中显示。但是,我不断收到“ActiveX 组件无法创建对象”错误。

为了尝试确定 COM 接口的设置/配置中是否存在错误,我创建了一个单独的 .Net 库作为我的解决方案的一部分,其中只有一个基本类和方法来返回“Hellow World”。这实际上按预期工作,即我在 VBA 应用程序的“引用”对话框中注册它,并可以实例化它并运行“HelloWorld”方法。

Dim simple as SimpleInterface.MyClass
Set simple = New SimpleInterface.MyClass

MsgBox simple.HelloWorld("Say Hello")

然后我在我的新基本 VS 项目中引用我想要的项目(业务逻辑)并在此处调用一个方法,然后在我的简单项目中创建另一个方法以公开为 COM 接口。我按照上面的方法取消注册dll并注册。

然后在我的 VBA 应用程序中取消选择 .tlb 文件,关闭它重新打开它,然后重新引用它,然后尝试运行代码。这是我得到“ActiveX 组件无法创建对象”的时候。我假设这与我的项目中的依赖 dll 有关,但我不确定,因为错误的细节很少。

我不确定我应该在这里做什么?我是否需要注册所有其他依赖的 dll,即我有大约 2 或 3 个外部 dll,我只是在 VS 项目中引用它们?有人可以告诉我如何找到更多详细信息,即哪个是确切的违规 dll?

【问题讨论】:

    标签: .net vba dll com activex


    【解决方案1】:

    “ActiveX 组件无法创建对象”错误通常意味着定位程序集或其依赖项之一时出现问题,或者程序集不包含任何具有请求的 ProgID 的公共类。要获取有关程序集加载故障排除的更多详细信息,我建议使用Assembly Binding Log Viewer

    需要检查的一些事项

    • 所以您实际上使用的是 64 位版本的 MS Office? (我一直认为 32 位版本仍然是最常用的版本,因为 64 位和 32 位版本在文件格式/Excel 文档等限制方面不兼容,但也许这是不再是这种情况了...?)
    • 您在编译 Visual Studio 项目时选择了什么目标平台?
    • 是否曾在项目设置中选中“注册 COM 互操作”复选框来编译项目?

    我在这里得到的是:任何可能您实际上正在为错误的平台/位数构建/注册(即,与您的 MS Office 安装的位数不匹配)?是否存在正确位数的旧注册,这可以解释为什么尽管针对错误的目标平台构建,但您仍然在 VBA IDE 的“引用”对话框中看到类型库?

    通过 COM 互操作公开 .NET 类时要记住的另一件大事

    默认情况下,Visual Studio 将为您的公开类生成新的随机ProgID GUIDs每次编译项目时。这就是为什么在重新编译您的 .NET 项目后,您必须经历删除引用然后将它们重新添加回 VBA IDE 以使事情再次工作的麻烦。

    不仅如此,它还会用大量过时的键使注册表变得混乱,除非您确保在用新编译的版本覆盖之前始终取消注册 (RegAsm /u /tlb) 程序集。

    为了防止这些事情发生,您应该使用ProgID attributes 在 .NET 代码中的 COM 公开类上显式设置 ProgID GUID。还建议使用ComVisible attribute,并在程序集级别将其设置为 false,并仅在需要向 COM 公开的类型上显式设置为 true。

    关于 .NET 依赖项

    您只需注册包含组件“入口点”的 DLL,即您从 VBA 调用的方法。不过,.NET 运行时需要能够找到依赖项,就像它对任何类型的 .NET 程序集所做的一样。这通常通过将依赖项的副本保存在与入口点 DLL 相同的文件夹中来实现。默认情况下,Visual Studio 通常会将依赖项复制到输出文件夹以供程序集/项目引用使用,GAC 中存在的程序集除外。

    如何使用 Visual Studio 调试器

    您可以通过将 Visual Studio 调试器附加到正在运行的excel.exe 进程(菜单中的Debug > Attach to Process)来调试从 VBA 调用的 .NET 代码。确保在 Excel 进程的类型列中提到了“托管”,并且调试器将附加到该列(应该自动发生,除非您修改了设置)。

    如果 Excel 进程未提及“托管”,则表示 Excel 尚未加载您的程序集;尝试在创建 COM 对象的语句之后立即使用断点运行 VBA 代码,然后再次尝试附加调试器。

    附加 Visual Studio 调试器后,您将可以访问有关正在发生的事情的更多信息。然后,只要抛出 .NET 异常,您就可以让 VS 调试器中断,您还可以添加断点并单步执行 .NET 代码。如果您还没有,真的值得研究。

    【讨论】:

    • 嗨 - 谢谢你的cmets。你是对的,我使用的是 32 位版本的 Excel。我以为我是 64 位...我将倒带一切并测试这些东西 - 再次...这是一个缓慢而费力的过程。我只是假设它有时会起作用,即来自一个简单的项目,所以我认为它会起作用。
    • 好的....谢谢...非常感谢!我现在遇到了一个不同的错误,但我认为你肯定让我走上了正确的道路。我现在得到一个“调用目标抛出异常”。我在我的简单类上创建了 2 个方法 - 第一个只返回“Hello World”,第二个尝试在我的业务逻辑项目中执行一个方法,这是我得到的错误。我认为我需要通过您的一些建议来进一步探索这一点,即设置一个常量 ProjgID GUIDS
    • @GlenHong:不客气,我很高兴你发现我的回答很有帮助。我现在添加了一些关于 .NET 依赖项和使用 Visual Studio 调试 .NET 部件的更多信息 :-)
    • 感谢所有cmets!经过几天的反复试验,真的是救生员!我找不到太多关于这些东西的文档。真的只是像你们这种明明在这方面有过扎实经验的cmet!再次感谢!我还没有完全让它工作,但你回答我确定已经回答了我原来的问题!
    • @mbj 感谢您为回答这个问题所做的努力,因为我遇到了与 Glen Hong 类似的问题。我发现我的问题是使用 64 位 regasm.exe。我更改为 32 位版本,它解决了我的问题。干杯
    猜你喜欢
    • 2011-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多