简体   繁体   English

使用 unmamagedexports 从 Access VBA 调用 C# DLL 时出现 VBA 错误 49 和错误 424

[英]VBA error 49 and error 424 when calling C# DLL from Access VBA using unmamagedexports

In our environment our main application uses MS Access for a front-end.在我们的环境中,我们的主要应用程序使用 MS Access 作为前端。 The back-ends are Access, MySQL and MariaDB.后端是 Access、MySQL 和 MariaDB。 Some of the routines we need are only available in C# so we have to be able to call .NET dll routines from VBA.我们需要的一些例程仅在 C# 中可用,因此我们必须能够从 VBA 调用 .NET dll 例程。 I did some testing with registered dlls (using RegASM) and it worked fine.我对注册的 dll 进行了一些测试(使用 RegASM)并且它运行良好。 However, for the installs on client machines, we really need to be able to get to the shared dlls WITHOUT registering them.但是,对于客户端计算机上的安装,我们确实需要能够在不注册它们的情况下访问共享的 dll。

I have been trying to get dynamically loaded libraries in MS Access VBA to work for a long time now.很长一段时间以来,我一直试图在 MS Access VBA 中动态加载库。 I thought I was close when I found this example: Canonical: How to call .NET methods from Excel VBA当我发现这个例子时,我以为我已经接近了: Canonical: How to call .NET methods from Excel VBA

I typed in the example verbatim and built it using Visual Studio 2017 Community.我逐字输入示例并使用 Visual Studio 2017 社区构建它。 Then I tried to run it in two different test environments.然后我尝试在两个不同的测试环境中运行它。 The first was a Windows 7 Pro (64 bit) box with MS Office Pro 2010 (32 bit).第一个是带有 MS Office Pro 2010(32 位)的 Windows 7 Pro(64 位)盒子。 The second test box has Windows 10 Pro (64 bit) and MS Office 2016 Pro (64 bit).第二个测试盒有 Windows 10 Pro(64 位)和 MS Office 2016 Pro(64 位)。 The result was the same on both, except for the error number/message.除了错误编号/消息外,两者的结果都是相同的。

Here is the sample code from the above link (I hope reposting the snippet is not a breach of etiquette. I wanted to make this post easier to follow):这是来自上述链接的示例代码(我希望重新发布代码片段不是违反礼仪。我想让这篇文章更容易理解):

[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();
    }
}

Here is the VBA code.这是 VBA 代码。 The only difference is that I did not use the "PtrSafe" qualifier in the Access 2010 32 bit test, but I did use it for the Access 2016 64 bit Access test.唯一的区别是我没有在 Access 2010 32 位测试中使用“PtrSafe”限定符,但我确实在 Access 2016 64 位 Access 测试中使用了它。 I set the Visual Studio Platform Target to x86 for the test with 32 bit Access and to x64 for the 64 bit Access.我将 Visual Studio Platform Target 设置为 x86 以进行 32 位访问测试,将 64 位访问设置为 x64。 Other than that, everything was the same.除此之外,一切都一样。

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

When the code is run, the errors always occur at the "Set mObj" line.代码运行时,错误总是发生在“Set mObj”行。

In the Access 2010 32 bit test, the error is:在Access 2010 32位测试中,错误为:

Run-time error '49': Bad DLL calling convention运行时错误“49”:错误的 DLL 调用约定

In the Access 2016 64 bit test, the error is:在Access 2016 64位测试中,错误为:

Run-time error '424': Object required运行时错误“424”:需要对象

On both tests, I ran DumpBin and the result seemed fine:在这两个测试中,我都运行了 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

>

Based upon a few other posts here on stackoverflow, I also experimented with the CallingConvention parameter on the DllExport but the result was always the same.基于 stackoverflow 上的其他一些帖子,我还尝试了 DllExport 上的 CallingConvention 参数,但结果始终相同。 I was very surprised that I couldn't get the example to work as I had entered it directly from the other post and I double-checked to make sure it was copied correctly.我很惊讶我无法让示例工作,因为我直接从另一篇文章输入了它,我再次检查以确保它被正确复制。 Any help would be greatly appreciated.任何帮助将不胜感激。

Your declaration for the DLL is incomplete or missing Data Type .您对 DLL 的声明不完整或缺少Data Type Change改变

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

to

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

Note笔记

Previous versions of Visual Basic allowed you to declare parameters As Any, meaning that data of any data type could be used.以前版本的 Visual Basic 允许您将参数声明为 As Any,这意味着可以使用任何数据类型的数据。 Visual Basic requires that you use a specific data type for all Declare statements. Visual Basic 要求您对所有 Declare 语句使用特定的数据类型。

read more here and try again. 在此处阅读更多信息并重试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM