首页 > 解决方案 > 使用 unmamagedexports 从 Access VBA 调用 C# DLL 时出现 VBA 错误 49 和错误 424

问题描述

在我们的环境中,我们的主应用程序使用 MS Access 作为前端。后端是 Access、MySQL 和 MariaDB。我们需要的一些例程仅在 C# 中可用,因此我们必须能够从 VBA 调用 .NET dll 例程。我对注册的 dll 进行了一些测试(使用 RegASM),它运行良好。但是,对于客户端计算机上的安装,我们确实需要能够在不注册共享 dll 的情况下访问它们。

我一直在尝试让 MS Access VBA 中的动态加载库能够工作很长时间。当我找到这个例子时,我以为我已经很接近了:Canonical: How to call .NET methods from Excel VBA

我逐字输入示例并使用 Visual Studio 2017 Community 构建它。然后我尝试在两个不同的测试环境中运行它。第一个是带有 MS Office Pro 2010(32 位)的 Windows 7 Pro(64 位)盒子。第二个测试盒有Windows 10 Pro(64位)和MS Office 2016 Pro(64位)。两者的结果是相同的,除了错误号/消息。

这是来自上述链接的示例代码(我希望重新发布该片段不会违反礼节。我想让这篇文章更容易理解):

[ComVisible(true), ClassInterface(ClassInterfaceType.AutoDual)]
public class YOUR_MAIN_CLASS
{
    [return: MarshalAs(UnmanagedType.BStr)]
    public string FN_RETURN_TEXT(string iMsg)
    {

        return "You have sent me: " + iMsg + "...";
    }
}


static class UnmanagedExports
{
    [DllExport]
    [return: MarshalAs(UnmanagedType.IDispatch)]
    static Object YOUR_DLL_OBJECT()
    {
        return new YOUR_MAIN_CLASS();
    }
}

这是VBA代码。唯一的区别是我在 Access 2010 32 位测试中没有使用“PtrSafe”限定符,但我在 Access 2016 64 位 Access 测试中使用了它。我将 Visual Studio Platform Target 设置为 x86 以进行 32 位访问的测试,将 64 位访问设置为 x64。除此之外,一切都一样。

Option Compare Database
Option Explicit

Public Declare PtrSafe Function LoadLibrary Lib "kernel32" _
    Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr

Public Declare PtrSafe Function YOUR_DLL_OBJECT Lib "NonRegisteredDLL.dll" ()

Public Sub TestLoad()

    LoadLibrary ("C:\Users\lab\Documents\Visual Studio 2017\Projects\NonRegisteredDLL\NonRegisteredDLL\bin\Debug\NonRegisteredDLL.dll")

    Dim mObj As Object


' Error occurs on next line
Set mObj = YOUR_DLL_OBJECT()


    Debug.Print mObj.FN_RETURN_TEXT("Testing...")

End Sub

运行代码时,错误总是出现在“Set mObj”行。

在Access 2010 32位测试中,错误为:

运行时错误“49”:错误的 DLL 调用约定

在Access 2016 64位测试中,错误为:

运行时错误“424”:需要对象

在这两个测试中,我都运行了 DumpBin,结果看起来还不错:

>dumpbin nonregistereddll.dll /exports

Dump of file nonregistereddll.dll

File Type: DLL

  Section contains the following exports for \NonRegisteredDLL.dll

    00000000 characteristics
    5C0FF158 time date stamp Tue Dec 11 10:18:16 2018
        0.00 version
           0 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          0    0 0000283E YOUR_DLL_OBJECT

  Summary

        2000 .reloc
        2000 .rsrc
        2000 .sdata
        2000 .text

>

根据 stackoverflow 上的其他一些帖子,我还尝试了 DllExport 上的 CallingConvention 参数,但结果始终相同。我很惊讶我无法让这个例子工作,因为我是直接从另一个帖子输入的,我仔细检查以确保它被正确复制。任何帮助将不胜感激。

标签: c#vbams-accessloadlibraryunmanagedexports

解决方案


您对 DLL 的声明不完整或缺失Data Type。改变

Public Declare PtrSafe Function YOUR_DLL_OBJECT Lib "NonRegisteredDLL.dll" ()

Public Declare PtrSafe Function YOUR_DLL_OBJECT Lib "NonRegisteredDLL.dll" () As Object

笔记

以前版本的 Visual Basic 允许您将参数声明为 Any,这意味着可以使用任何数据类型的数据。Visual Basic 要求您对所有 Declare 语句使用特定的数据类型。

在此处阅读更多内容并重 试。


推荐阅读