Параметры функции UnmanagedExports — причина VBA 49 Неверное соглашение о вызовах DLL

Я не могу заставить свою C# Dll работать с моей электронной таблицей Excel Macro для вызова функции в библиотеке Dll. Я могу вызвать функцию, если у нее нет параметров, способных вернуть ожидаемое значение. Но я не могу добиться успеха вызова Dll из VBA, когда добавляю входные параметры в функцию.

Общая сумма моего модуля С# выглядит следующим образом:

using System;
using System.Runtime.InteropServices;
using RGiesecke.DllExport;

namespace RSExternalInterface
{
    public class RSExternalInterface
    {
        [DllExport("add", CallingConvention = CallingConvention.Cdecl)]
        public static int TestExport(int left, int right)
        {
            return left + right;
        }
    }
}

Мой код VBA выглядит следующим образом.

Декларация модуля:

Declare Function add Lib "C:\Program Files\RS\RSExternalInterface.dll" (ByVal Left As Integer, ByVal Right as Integer) As Integer

Вызов приведенной выше функции внутри подпрограммы события нажатия кнопки выглядит следующим образом:

result = add (5, 7)

В момент выполнения вышеуказанной строки возникает ошибка 49.

Я пробовал следующее:

  1. Удален «ByVal» в объявлении функции VBA.
  2. Убрано и добавлено оформление в функции C#, после [DllExports ...]
  3. Убежден, что я ориентируюсь на правильную платформу ЦП
  4. Удалены параметры в объявлении и вызове, чтобы убедиться, что функция DLL доступна.

Что я делаю неправильно?


person Willie Marais    schedule 25.01.2018    source источник
comment
Вам может понадобиться ввести Lib после add   -  person K.Dᴀᴠɪs    schedule 25.01.2018
comment
Lib действительно есть в моем коде. Опечатка для того, чтобы не добавить это выше. Исправленный.   -  person Willie Marais    schedule 26.01.2018
comment
Будет ли это работать, если вы удалите As Integer из своих объявлений? Просто из любопытства.   -  person K.Dᴀᴠɪs    schedule 26.01.2018
comment
Проверьте C# .dll с помощью Dependency Walker и посмотрите, отображаются ли экспортированные функции. Я скопировал/вставил ваш точный код, но моя .dll, похоже, ничего не экспортирует. Загрузка функции из VBasic не удалась (очевидно), поскольку ее невозможно найти.   -  person CristiFati    schedule 17.02.2018


Ответы (1)


Я удивлен, что "Соглашение о вызовах" из заголовка вопроса и CallingConvention из кода C# ничего не значат (хотя я не исключаю вводящее в заблуждение сообщение об ошибке на < сторона em>MS).

Соглашение о вызовах похоже на протокол при выполнении подпрограмм между:

  • вызываемый - подпрограмма (функция, процедура (или функция, которая ничего не возвращает или возвращает void))
  • вызывающий — код (также подпрограмма — может быть main), который вызывает/выполняет вызываемый

и определяет:

  1. Кто обрабатывает (push / pop) аргументы функции в стеке (вызываемый / вызывающий) при ее выполнении
  2. Порядок аргументов в стеке (справа -> слева или слева -> справа)

Из-за №1. важно, чтобы 2 стороны (вызываемый / вызывающий) были синхронизированы в отношении соглашение о вызовах, в противном случае они будут мешать друг другу, и стек в конечном итоге будет поврежден. «Неправильное соглашение о вызовах DLL» означает именно это: 2 не синхронизированы.

  • Вы получаете правильное поведение для функции без аргументов, потому что нечего проталкивать / извлекать в/из стека - это не означает, что нет никаких ошибка; ошибка есть, но она не встречается
  • Дополнительные сведения: [MSDN]: передача и наименование аргументов Соглашения. Обратите внимание на различия между __stdcall и __cdecl, а также на то, что они относятся к 32-разрядной (x86) архитектуре. AFAIK (также поддерживается ошибкой), исполняемый файл Excel (в целом MSOffice) является 32-битным
  • Согласно [ MSDN]: поле DllImportAttribute.CallingConvention (которое, я полагаю, также относится к DllExport):
    #P5#

Я взял ваш код и немного поиграл с ним.

code.cs:

using System;
using System.Runtime.InteropServices;
using RGiesecke.DllExport;


namespace RSExternalInterface
{
    public class RSExternalInterface
    {
        [DllExport("add")]
        public static int TestExport(int left, int right)
        {
            int ret = left + right;
            String s = String.Format("C# Func - add: {0} + {1} = {2}", left, right, ret);
            Console.WriteLine(s);
            return ret;
        }

        [DllExport("dbl", CallingConvention = CallingConvention.Winapi)]
        public static int TestExport1(int value)
        {
            int ret = value * 2;
            String s = String.Format("C# Func - dbl: {0} * 2 = {1}", value, ret);
            Console.WriteLine(s);
            return ret;
        }

        [DllExport("none", CallingConvention = CallingConvention.StdCall)]
        public static void TestExport2(int value)
        {
            String s = String.Format("C# Func - none: {0}", value);
            Console.WriteLine(s);
        }

    }
}

main.vb:

Module main

    Declare Function add Lib "CsDll.dll" (ByVal Left As Integer, ByVal Right As Integer) As Integer
    Declare Function dbl Lib "CsDll.dll" (ByVal Value As Integer) As Integer
    Declare Sub none Lib "CsDll.dll" (ByVal Value As Integer)

    Sub Main()
        Console.WriteLine("64 bit OS: {0}{1}64 bit process: {2}{1}", Environment.Is64BitOperatingSystem, Environment.NewLine, Environment.Is64BitProcess)
        Dim i As Integer
        none(-7659)
        i = dbl(78)
        i = add(22, -13)

    End Sub

End Module

Примечания:

  • Мне не удалось создать его и запустить в Excel, поэтому я попробовал второйй лучший способ: сделать это из VB. Обратите внимание, что я не разбираюсь ни в C#, ни в VB.
  • At the beginning (as I stated in a comment), I wasn't able to export anything from the C# .dll. Looking at UnmanagedExports.nuspec (part of the nupkg):
    • You have to set your platform target to either x86, ia64 or x64. AnyCPU assemblies cannot export functions.
  • Изменил Платформу с Любой процессор (по умолчанию VStudio) на x64 (по ошибке), и все заработало нормально ( несмотря на CallingConvention.Cdecl), только после установки x86 я смог воспроизвести проблему
  • В любом случае, код (C#) содержит 3 способа (не) указания соглашения о вызовах, которые будут работать из VB

Вывод (VStudio 2015 (сообщество)):

64 bit OS: True
64 bit process: False

C# Func - none: -7659
C# Func - dbl: 78 * 2 = 156
C# Func - add: 22 + -13 = 9

Вот (древний) URL, в котором также упоминается ваша ошибка: [MSDN]: неправильное соглашение о вызовах DLL (ошибка 49)

person CristiFati    schedule 17.02.2018