来自 vba 引用的 vb.net 编译的 dll 中的“运行时错误 '453' 找不到 dll 入口点”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2822256/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-11 11:38:39  来源:igfitidea点击:

"run-time error '453' can't find dll entry point" from vb.net compiled dll referenced by vba

vb.netvbadllruntime-errorentry-point

提问by BHurst

I am coding in vb.net through visual studio 2008. I have successfully compiled a dll file from my code but I continue to get "Run-time error '453'" when I try to reference the dll in vba. I understand there is some sort of compiling error that occurs when using vb.net. Does anyone have any suggestions to fix/overcome this issue? I would like to avoid translating the code to another language as much as possible.

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

Here is a simple sample code that I have been trying to get functioning:

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

Example.dll:

示例.dll:

Public Class Class1

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

        y = x * x

        Return 0

    End Function

End Class

Macro in Example.xlsx:

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

Thank you, Katlynn

谢谢你,凯特琳

回答by Chris Haas

Its been a while since I've done this so I'm not sure if its necessary anymore but did you try adding all of the COM attributes?

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

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

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

回答by Albert D. Kallal

Ok, a truckload of issues here and assumptions are incorrect.

好吧,这里有一卡车的问题和假设是不正确的。

First up, when you use declare in VBA to a .dll, you cannot use relative path names.

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

So you have:

所以你有了:

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

You can't use \Example.dll

您不能使用 \Example.dll

You have to specify the FULL path name. Eg:

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

C:\mytestApp\Example.dll

So even if vb.net did produce a working .dll, you have to use a full path name – no relative path name is allowed.

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

You can place the .dll in the standard windows path names that are searched for .dll's (so c:\windows\system32), and thus NOT have to use a full path name.

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

However, these days with security, adding or just tossing a .dll into a windows system folder tends to have a LOT of security issues and HUGE hassles. (windows makes this hard, and so does any virus software). So you have to use a full path name.

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

Next up:

接下来:

Using declare in VBA is a means to call the windows API, or what we call windows x32 bit library code. This is not COM (ActiveX), but has to be raw windows x32 (or x64) native windows code.

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

So this is not a ActiveX, or “com” object, but raw code that you call. A standard vb.net (or any .net language) does NOT produce windows native code. The correct term is

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

Managed code = .net code. This code is NOT native windows code.

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

Un-managed code = raw windows code.

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

So you have to create un-managed code to use DECLARE in VBA.

因此,您必须创建非托管代码才能在 VBA 中使用 DECLARE。

So you have to use: X86 assembler C++ VB6 Or ANY development tool that can produce raw x32 (or if using access x64, then raw x64 native windows code).

因此,您必须使用:X86 汇编程序 C++ VB6 或任何可以生成原始 x32 的开发工具(或者如果使用访问 x64,则使用原始 x64 本机 Windows 代码)。

In visual studio these days you "can" produce native windows code, but you have to use un-managed code, and that thus means c++. (c#, or vb.net don't produce native code or dll's).

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

So you can use c++, or VB6 or even a assembler to create these .dll's.

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

Such .dlls do NOT require registration. And as noted you don't create an “instance” of the object in VBA code, but call it directly.

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

These types of .dll's (simple external library code calls) thus do not appear as a COM object. And if you in VBA editor go tools->references, then you not see these libraries appear. However, they can be ease to use, since you don't have to create a instance of the object I VBA code - you just call such code like your example.

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

Because the path name is hard coded with this approach, then it often a pain to use the DECLARE statement (since it is determined at VBA compile time, and not runtime). This would mean you have to place that .dll in the SAME location for each computer you deploy to. If you move or change the folder, then your code would fail.

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

To get around this issue, you can use the LOADLIBARY call in VBA. This will allow you at runtime to set (determine) the location of the .dll. So most developers will thus simple place the .dll in the SAME folder as the running application (same folder as the Access or in this case Excel file).

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

However, this assumes you create a standard windows .dll.

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

Can I create such native windows .dll's in .net with vb.net?

我可以使用 vb.net 在 .net 中创建这样的本机 Windows .dll 吗?

It turns out you can with some external add-in's for VS. I often use this approach to create these dll's, since then I don't have to build COM interface code, and it is VERY simple to use.

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

I then combine the above with VBA using a LOADLIBRARY call, and that works quite well. So in VS you can use a NuGet package (add in) and pick a .dll export add-in utility. There are several, but I used the RGeseke DLLimport with great success. These are free 3rd party choices here.

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

While the above reduces some hassles, you will have to adopt the VBA loadlibrary code to make this a practical choice (or always place the .dll in the same location). I also recommend this approach if you have some existing .dll's, and want to interface to that code but don't want to learn say c++. So I do use this approach to consume existing dll's in vb.net, and thus in turn from Access. In effect this trick allows you to write interfaces to windows .dll code in a nice familiar language like vb.net.

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

However, if you not used LOADlibrary from VBA (and VB6) in the past, and are not up to speed, then I will suggest you choose the next option.

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

Creating COM (ActiveX) from vb.net

从 vb.net 创建 COM (ActiveX)

This is likely the best approach. And it is the most common approach. However, you have to trade off having to create a COM object in vb.net, and THEN register it on the target computer.

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

So, the only hassle is this requirement to register the .dll on the target computer.

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

Having to register (regasm.exe) the COM object on the target machine often requires elevated rights. And with companies so security conscious these days, then this installing requirement can be a hassle, but it still likely the best option.

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

Here is a working example of your code in vb.net.

这是您在 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

Note the above including of interop, and the autoDuel setting in code. This is what allows .net to create a standard windows COM object interface that can be consumed by VBA, VB6, windows scripting, or just any platform that supports COM objects.

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

Settings you need for this to work:

使其工作所需的设置:

FORCE the .net project to x86. (you using Excel x32).

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

So in VS go build->configuration manager. Click on platform in the grid, and choose new, choose x86 and click ok.

所以在 VS 中去构建-> 配置管理器。单击网格中的平台,然后选择新建,选择 x86 并单击确定。

You should now have this: enter image description here

你现在应该有这个: 在此处输入图片说明

Next up, ensure that the project is made com visible. This check box is USUALLY checked for you by default. All .net classes tend to be marked this way. But I seen it become un-checked when you mess with the previous step of changing the build to x86. So do a quick look at this setting.

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

Project->properties

项目->属性

Now on Application area, click on assembly information box.

现在在应用程序区域,单击装配信息框。

You need to ensure this check box is set:

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

enter image description here

在此处输入图片说明

So above takes only a few seconds.

所以上面只需要几秒钟。

So check the above (they are usually are already set for you).

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

Next, we have to tell VS to register this COM object on our development computer. (this is that regasm.exe requirement).

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

So, in compile area, check this box:

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

enter image description here

在此处输入图片说明

Now, the above check box in VS is ONLY for your development computer and convenience. It simply does a regasm for you, and this is the magic that exposes the class as a COM object for use in VBA or ANY system that supports COM.

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

Note that the above check box is ONLY for your convenience on your development machine. It does NOT change, modify or do ANYTHING to the code or project.

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

Now to deploy this code to other machines, you have to provide a batch file or some other means to execute the regasm.exe command. As I pointed out, these does make deployment a greater hassle then the .dll approach, but you trade off other ease of coding here.

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

As this point, compile (build) the above.

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

Once you done so, you find now in the VBA editor, you can go tools->references and you find your project as a registered COM object for consuming in VBA.

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

You see this: (my project was call Testcom2.

你看到这个:(我的项目被称为 Testcom2。

enter image description here

在此处输入图片说明

And note that once you do set this reference, you MUST EXIT excel if you make changes or re-compile the .net project. (because EXCEL will have locked and have that .dll in use once you set this reference). So just remember if you going to re-compile the .net code, make sure you exit Excel.

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

And I changed you code a bit, since a function returns a value, and you always returning 0. You could use a call and use a Sub if you wanted, but you HAVE function defined in vb.net and did not define a sub.

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

So in VBA, we now have this:

所以在 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

Note how even intel-sense works as I type, so the function show up as a method in VBA.

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

enter image description here

在此处输入图片说明

And even the types and parms show up while you type in VBA such as:

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

enter image description here

在此处输入图片说明

And hitting f5 in VBA to run the code, we get this as output:

在 VBA 中点击 f5 来运行代码,我们得到它作为输出:

100