【问题标题】:"run-time error '453' can't find dll entry point" from vb.net compiled dll referenced by vba“运行时错误'453'找不到dll入口点”来自vba引用的vb.net编译的dll
【发布时间】:2010-05-12 19:47:25
【问题描述】:

我正在通过 Visual Studio 2008 在 vb.net 中进行编码。我已经从我的代码中成功编译了一个 dll 文件,但是当我尝试在 vba 中引用该 dll 时,我继续收到“运行时错误 '453'”。我知道使用 vb.net 时会出现某种编译错误。有没有人有任何建议来解决/克服这个问题?我想尽可能避免将代码翻译成另一种语言。

这是我一直在尝试运行的简单示例代码:

Example.dll:

Public Class Class1

    Function Square(ByVal x As Double, ByRef y As Double)

        y = x * x

        Return 0

    End Function

End Class

Example.xlsx 中的宏:

Private Declare Function Square Lib "\Example.dll" (ByRef x As Double, ByRef y As Double)

Sub Test()

Dim x, y As Double

x = 2
y = 0

Call Square(x, y)

MsgBox (y)

End Sub

谢谢你, 凯特琳

【问题讨论】:

    标签: vb.net vba dll runtime-error entry-point


    【解决方案1】:

    好的,这里有一大堆问题和假设是不正确的。

    首先,当您在 VBA 中对 .dll 使用声明时,不能使用相对路径名。

    所以你有:

    Private Declare Function Square Lib 
    "\Example.dll" (ByRef x As Double, ByRef y As Double)
    

    你不能使用 \Example.dll

    您必须指定完整路径名。例如:

    C:\mytestApp\Example.dll
    

    因此,即使 vb.net 确实生成了一个有效的 .dll,您也必须使用完整的路径名——不允许使用相对路径名。

    您可以将 .dll 放在用于搜索 .dll 的标准 Windows 路径名中(例如 c:\windows\system32),因此不必使用完整路径名。

    然而,如今有了安全性,在 Windows 系统文件夹中添加或仅添加 .dll 往往会带来很多安全问题和巨大的麻烦。 (Windows 使这变得困难,任何病毒软件也是如此)。所以你必须使用完整的路径名。

    接下来:

    在VBA中使用declare是一种调用windows API的方法,也就是我们所说的windows x32位库代码。这不是 COM (ActiveX),但必须是原始 windows x32(或 x64)原生 windows 代码。

    所以这不是 ActiveX 或“com”对象,而是您调用的原始代码。标准的 vb.net(或任何 .net 语言)不会生成 Windows 本机代码。正确的说法是

    托管代码 = .net 代码。此代码不是本机 Windows 代码。

    非托管代码 = 原始 Windows 代码。

    所以你必须创建非托管代码才能在 VBA 中使用 DECLARE。

    所以你必须使用: X86 汇编器 C++ VB6 或任何可以生成原始 x32 的开发工具(或者如果使用 access x64,则使用原始 x64 本机 Windows 代码)。

    如今,在 Visual Studio 中,您“可以”生成本机 Windows 代码,但您必须使用非托管代码,这意味着 C++。 (c# 或 vb.net 不生成本机代码或 dll)。

    因此您可以使用 c++、VB6 甚至汇编程序来创建这些 .dll。

    此类 .dll 不需要注册。如前所述,您不会在 VBA 代码中创建对象的“实例”,而是直接调用它。

    因此,这些类型的 .dll(简单的外部库代码调用)不会显示为 COM 对象。如果您在 VBA 编辑器中转到工具-> 参考,那么您不会看到这些库出现。但是,它们易于使用,因为您不必创建对象 I VBA 代码的实例 - 您只需像您的示例一样调用此类代码。

    因为路径名是用这种方法硬编码的,所以使用 DECLARE 语句通常很痛苦(因为它是在 VBA 编译时确定的,而不是在运行时确定的)。这意味着您必须将该 .dll 放在您部署到的每台计算机的相同位置。如果您移动或更改文件夹,那么您的代码将会失败。

    要解决此问题,您可以在 VBA 中使用 LOADLIBARY 调用。这将允许您在运行时设置(确定).dll 的位置。因此,大多数开发人员会简单地将 .dll 放在与正在运行的应用程序相同的文件夹中(与 Access 或在本例中为 Excel 文件相同的文件夹)。

    但是,这假设您创建了一个标准的 windows .dll。

    我可以用 vb.net 在 .net 中创建这样的原生 windows .dll 吗?

    事实证明,您可以使用一些用于 VS 的外部加载项。我经常使用这种方法来创建这些dll,从此我不必构建COM接口代码,并且使用起来非常简单。

    然后我使用 LOADLIBRARY 调用将上述内容与 VBA 结合起来,效果很好。因此,在 VS 中,您可以使用 NuGet 包(插件)并选择 .dll 导出插件实用程序。有几个,但我使用 RGeseke DLLimport 非常成功。这些是免费的第 3 方选择。

    虽然上述方法减少了一些麻烦,但您必须采用 VBA 加载库代码才能使这成为一个实际的选择(或始终将 .dll 放在同一位置)。如果您有一些现有的 .dll,并且想要与该代码交互但不想学习 c++,我也推荐这种方法。所以我确实使用这种方法来使用 vb.net 中现有的 dll,从而反过来从 Access 中使用。实际上,这个技巧允许您使用熟悉的语言(如 vb.net)编写 Windows .dll 代码的接口。

    但是,如果您过去没有使用 VBA(和 VB6)中的 LOADlibrary,并且速度不快,那么我建议您选择下一个选项。

    从 vb.net 创建 COM (ActiveX)

    这可能是最好的方法。这是最常见的方法。但是,您必须权衡必须在 vb.net 中创建一个 COM 对象,然后在目标计算机上注册它。

    因此,唯一的麻烦是在目标计算机上注册 .dll 的要求。

    必须在目标计算机上注册 (regasm.exe) COM 对象通常需要提升权限。如今,随着公司如此注重安全性,这种安装要求可能会很麻烦,但它仍然可能是最佳选择。

    这是您在 vb.net 中的代码的工作示例。

    Imports System.Runtime.InteropServices
    
     <ClassInterface(ClassInterfaceType.AutoDual)>
    Public Class Class1
        Function Square(ByVal x As Double) As Double
    
           Dim y As Double
           y = x * x
    
           Return y
    
       End Function
    
    End Class
    

    请注意上述包括互操作和代码中的 autoDuel 设置。这就是允许 .net 创建标准 windows COM 对象接口的原因,该接口可由 VBA、VB6、windows 脚本或任何支持 COM 对象的平台使用。

    为此工作所需的设置:

    将 .net 项目强制转换为 x86。 (您使用 Excel x32)。

    所以在 VS 中 go build-> 配置管理器。在网格中点击platform,选择new,选择x86,点击ok。

    你现在应该有这个:

    接下来,确保项目是 com 可见的。默认情况下,通常会为您选中此复选框。所有 .net 类都倾向于以这种方式标记。但是我看到当您将构建更改为 x86 的上一步弄乱时,它变得未选中。因此,请快速查看此设置。

    项目->属性

    现在在应用区域,点击组装信息框。

    您需要确保已设置此复选框:

    所以上面只需要几秒钟。

    所以请检查以上内容(它们通常已经为您设置好了)。

    接下来,我们必须告诉 VS 在我们的开发计算机上注册这个 COM 对象。 (这是 regasm.exe 的要求)。

    所以,在编译区,勾选这个框:

    现在,VS 中的上述复选框仅用于您的开发计算机和方便。它只是为你做一个 regasm,这就是将类公开为 COM 对象以在 VBA 或任何支持 COM 的系统中使用的魔法。

    请注意,上面的复选框只是为了您在开发机器上的方便。它不会更改、修改或对代码或项目做任何事情。

    现在要将此代码部署到其他机器,您必须提供批处理文件或其他方式来执行 regasm.exe 命令。正如我所指出的,与 .dll 方法相比,这些确实使部署更加麻烦,但您在此处牺牲了其他编码的便利性。

    至此,编译(构建)上述内容。

    完成此操作后,您现在可以在 VBA 编辑器中找到工具->引用,然后您会发现您的项目作为已注册的 COM 对象在 VBA 中使用。

    你看到了:(我的项目叫做 Testcom2。

    请注意,一旦您设置了此引用,如果您进行更改或重新编译 .net 项目,则必须退出 excel。 (因为一旦您设置了此引用,EXCEL 将被锁定并使用该 .dll)。所以请记住,如果您要重新编译 .net 代码,请确保退出 Excel。

    我稍微改变了你的代码,因为函数返回一个值,而你总是返回 0。如果你愿意,你可以使用调用并使用 Sub,但是你在 vb.net 中定义了函数并且没有定义一个子。

    所以在 VBA 中,我们现在有了这个:

    Sub TEst55()
    
      Dim cMySquare  As New TestCom2.Class1
    
      Dim a    As Double
      Dim b    As Double
    
      a = 10
    
      b = cMySquare.Square(a)
    
      Debug.Print b
    
    
    End Sub
    

    请注意,当我键入时,甚至 intel-sense 是如何工作的,因此该函数在 VBA 中显示为一个方法。

    当你在 VBA 中键入时,甚至类型和参数也会显示出来,例如:

    然后在 VBA 中按 f5 来运行代码,我们得到以下输出:

    100
    

    【讨论】:

      【解决方案2】:

      我已经有一段时间没有这样做了,所以我不确定它是否有必要,但您是否尝试添加所有 COM 属性?

      http://support.microsoft.com/Default.aspx?kbid=817248

      【讨论】:

      • 是的,我尝试使用 COMclass1 而不是默认的 Class1,并且“注册 COM 互操作”框已经被选中。上面的代码仍然产生错误。我也尝试将 dll 添加为参考,但我收到一个错误,例如“无法引用此文件”或类似的愚蠢。我还尝试像您提供的网站所建议的那样构建一个对象,但该对象没有正确构建。我觉得有一个我没有看到的漏洞......还有其他建议吗?
      猜你喜欢
      • 1970-01-01
      • 2015-07-19
      • 1970-01-01
      • 1970-01-01
      • 2022-01-19
      • 2012-12-08
      • 1970-01-01
      • 2017-10-22
      • 1970-01-01
      相关资源
      最近更新 更多