“运行时错误'453'无法从vb.net引用的vb.net编译的dll中找到dll入口点”

时间:2010-05-12 19:47:26

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

我正在通过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

谢谢你, Katlynn

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

好的,这里有很多问题和假设是不正确的。

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

所以你有

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

您不能使用\ Example.dll

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

C:\mytestApp\Example.dll

因此,即使vb.net确实生成了可运行的.dll,您也必须使用完整路径名-不允许使用相对路径名。

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

但是,近来,出于安全考虑,在Windows系统文件夹中添加或仅将.dll扔进去往往会带来很多安全问题和麻烦。 (Windows使这一点变得困难,任何病毒软件也是如此)。因此,您必须使用完整的路径名。

下一步:

在VBA中使用声明是一种调用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作为正在运行的应用程序简单地放置在SAME文件夹中(与Access相同的文件夹,在本例中为Excel文件)。

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

我可以使用vb.net在.net中创建此类本机Windows .dll吗?

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

然后我使用LOADLIBRARY调用将上述内容与VBA结合使用,效果很好。因此,在VS中,您可以使用NuGet包(加载项)并选择.dll导出加载项实用程序。有几种,但是我成功地使用了RGeseke DLLimport。这些是这里的第三方免费选择。

尽管上述内容减少了一些麻烦,但您将必须采用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中,转到build-> configuration manager。单击网格中的platform,然后选择new,选择x86,然后单击OK。

您现在应该拥有这个: enter image description here

接下来,请确保该项目在com中可见。默认情况下,通常会为您选中此复选框。所有.net类都倾向于用这种方式标记。但是我看到,当您对将内部版本更改为x86的上一步感到困惑时,它变得未经检查。因此,请快速浏览一下此设置。

项目->属性

现在在“应用程序”区域中,单击程序集信息框。

您需要确保选中此复选框:

enter image description here

所以上面只需要几秒钟。

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

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

因此,在编译区域中,选中此框:

enter image description here

现在,VS中的上述复选框仅用于开发计算机和方便使用。它只是为您带来重塑,这就是将类公开为COM对象的魔力,可在VBA或支持COM的任何系统中使用。

请注意,以上复选框仅是为了方便您在开发计算机上使用。它不会更改,修改或对代码或项目做任何事情。

现在要将此代码部署到其他计算机,您必须提供一个批处理文件或其他某种方式来执行regasm.exe命令。正如我所指出的那样,与.dll方法相比,这些确实使部署更加麻烦,但是您在这里权衡了其他易于编写的代码。

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

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

您看到的是:(我的项目叫Testcom2。

enter image description here

请注意,一旦设置了此引用,如果进行更改或重新编译.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中显示为一种方法。

enter image description here

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

enter image description here

然后在VBA中按f5键运行代码,我们将其作为输出:

100