Ошибка 49 VBA и ошибка 424 при вызове C# DLL из Access VBA с использованием unmamagedexports
В нашей среде наше основное приложение использует MS Access для внешнего интерфейса. Бэкэндами являются Access, MySQL и MariaDB. Некоторые из необходимых нам подпрограмм доступны только в C#, поэтому мы должны иметь возможность вызывать подпрограммы.NET dll из VBA. Я провел некоторое тестирование с зарегистрированными dll (используя RegASM), и оно работало нормально. Тем не менее, для установки на клиентских компьютерах нам действительно необходимо иметь доступ к общим dll без их регистрации.
Я давно пытаюсь заставить динамически загружаемые библиотеки в MS Access VBA работать. Я думал, что был близок, когда я нашел этот пример: Canonical: Как вызывать методы.NET из Excel VBA
Я набрал в качестве примера дословно и построил его с помощью сообщества Visual Studio 2017. Затем я попытался запустить его в двух разных тестовых средах. Первым был Windows 7 Pro (64-битный) с MS Office Pro 2010 (32-битный). Второй тестовый блок имеет 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. Единственное отличие состоит в том, что я не использовал квалификатор PtrSafe в 32-разрядном тесте Access 2010, но использовал его для 64-разрядного теста Access 2016. Я установил для Visual Studio Platform Target значение x86 для теста с 32-битным доступом и x64 для 64-битного доступа. Кроме этого все было одинаково.
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
В 64-разрядном тесте Access 2016 ошибка:
Ошибка времени выполнения '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
>
Основываясь на нескольких других сообщениях здесь о стековом потоке, я также экспериментировал с параметром CallingConvention в DllExport, но результат всегда был одинаковым. Я был очень удивлен, что не смог заставить пример работать, поскольку я ввел его непосредственно из другого поста, и я дважды проверил, чтобы убедиться, что он был скопирован правильно. Любая помощь будет принята с благодарностью.
1 ответ
Ваша декларация для 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.
прочитайте больше здесь и попробуйте снова.