c# - 使用 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 参数,但结果始终相同。我很惊讶我无法让这个例子工作,因为我是直接从另一个帖子输入的,我仔细检查以确保它被正确复制。任何帮助将不胜感激。
解决方案
您对 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 语句使用特定的数据类型。
在此处阅读更多内容并重 试。
推荐阅读
- sql-server - 将值插入另一个表中的特定行
- r - 如何将天气 API 嵌入到闪亮仪表板中
- python - python - 如何从python中的父类范围访问父覆盖函数?
- docker - Sonarqube 从 7.4-community 升级到 7.9 JVM 错误
- apache-kafka - 使用 spring kafka 的恰好一次语义
- json - 我可以使用powershell获取json中属性的层次结构路径吗?
- c++ - 数字到单词转换器 C++ 编码
- mongodb - Mongo shell 不能通过 kubectl cli 工作
- pytest - pytest 失败,没有回溯或显示代码
- excel - 当有空单元格时,如何对单元格的部分部分求和?