Ошибка 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.

прочитайте больше здесь и попробуйте снова.

Другие вопросы по тегам