Ошибка 49 VBA и ошибка 424 при вызове C # DLL из Access VBA с использованием unmamagedexports - PullRequest
0 голосов
/ 12 декабря 2018

В нашей среде наше основное приложение использует 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».

В 32-разрядном тесте Access 2010 ошибка:

Ошибка времени выполнения '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

>

Основано наНесколько других постов здесь о stackoverflow, я также экспериментировал с параметром CallingConvention на DllExport, но результат всегда был одинаковым.Я был очень удивлен, что не смог заставить пример работать, поскольку я ввел его непосредственно из другого поста, и я дважды проверил, чтобы убедиться, что он был скопирован правильно.Любая помощь будет принята с благодарностью.

1 Ответ

0 голосов
/ 12 декабря 2018

Ваше объявление для 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 позволяли объявлять параметры как любые, что означает, что данные любого типа данныхможет быть использован.Visual Basic требует, чтобы вы использовали определенный тип данных для всех операторов Declare.

Подробнее читайте здесь и повторите попытку.

...