简体   繁体   English

UnmanagedExports 函数参数 - 导致 VBA 49 错误的 DLL 调用约定

[英]UnmanagedExports Function Parameters - Cause VBA 49 Bad DLL Calling Convention

I am unable to get my C# Dll to work with my Excel Macro enable spreadsheet to call the function in the Dll.我无法让我的 C# Dll 与我的 Excel 宏一起使用电子表格来调用 Dll 中的函数。 I am able to call the function if it has no parameters, able to return the expected value.如果没有参数,我可以调用该函数,并能够返回预期值。 But I cannot get the Dll call from VBA to be successful when I add input parameters to the function.但是当我向函数添加输入参数时,我无法从 VBA 中成功调用 Dll。

The sum total of my C# module is as follows:我的 C# 模块的总和如下:

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;
        }
    }
}

My VBA Code is as follows.我的 VBA 代码如下。

Module Declaration:模块声明:

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

Call the function above, inside the click event sub of a button, is as follows:调用上面的函数,在按钮的单击事件子中,如下所示:

result = add (5, 7)

The moment the above line is executed, Error 49 comes up.执行上述行的那一刻,出现错误 49。

I have tried the following:我尝试了以下方法:

  1. Removed the "ByVal" in the VBA function declaration删除了 VBA 函数声明中的“ByVal”
  2. Removed and added the decoration in the C# function, after [DllExports ...]删除并添加了 C# 函数中的装饰,在 [DllExports ...] 之后
  3. Ensured that I target the correct CPU platform确保我的目标是正确的 CPU 平台
  4. Removed the parameters in the declaration and calling to ensure that the DLL function is accessible.删除了声明和调用中的参数,以确保可以访问 DLL 函数。

What am I doing wrong?我做错了什么?

I am surprised that " Calling Convention " from question title and CallingConvention from C# code didn't ring any bell (although I don't rule out a misleading error message on MS side).我感到奇怪的是,从问题的标题和“调用约定CallingConventionC#代码没响钟声任何(虽然我不排除在MS侧误导性的错误消息)。

Calling convention is like a protocol when executing subroutines, between:调用约定就像执行子程序时的协议,介于:

  • callee - the routine (function, procedure (or function that doesn't return anything, or returns void )) callee - 例程(函数、过程(或不返回任何内容或返回void函数))
  • caller - code (a subroutine as well - could be main ) that calls/executes the callee caller - 调用/执行被调用者的代码(也可以是子程序 - 可以是main

and determines:并确定:

  1. Who handles ( push / pop ) the function arguments on the stack ( callee / caller ) when executing it谁在执行时处理(推送/弹出)堆栈(被调用者/调用者)上的函数参数
  2. Arguments order on the stack ( right -> left or left -> right )堆栈上的参数顺序( right -> leftleft -> right

Because of #1.因为#1。 , it's important that the 2 parties ( callee / caller ) to be in synch regarding calling convention, otherwise they will setp on each other's toes, and the stack will eventually get corrupted. ,重要的是 2 方(被调用/调用方调用约定方面保持同步,否则他们会互相干扰,堆栈最终会被破坏。 " Bad DLL Calling Convention " means exactly this thing: the 2 are not in synch. 错误的 DLL 调用约定”就是这个意思:两者同步。

  • You get correct behavior for function without arguments, because there's nothing to push / pop to/from the stack - this doesn't mean that there isn't any error ;对于没有参数的函数,您可以获得正确的行为,因为没有任何东西可以推入/弹出堆栈-这并不意味着没有任何错误 the error is there but it's not encountered错误在那里,但没有遇到
  • More details: [MSDN]: Argument Passing and Naming Conventions .更多详细信息: [MSDN]:参数传递和命名约定 Note differences between __stdcall and __cdecl , and also note that they apply to 32bit ( x86 ) architecture .请注意__stdcall__cdecl之间的差异,还要注意它们适用于32 位 ( x86 ) 架构 AFAIK (also backed up by the error), Excel executable (as whole MSOffice ) is 32bit AFAIK (也由错误支持), Excel可执行文件(作为整个MSOffice )是 32 位
  • According to [MSDN]: DllImportAttribute.CallingConvention Field (which I assume also applies to DllExport ):根据[MSDN]: DllImportAttribute.CallingConvention Field (我认为这也适用于DllExport ):

    You set this field to one of the CallingConvention enumeration members.您将此字段设置为CallingConvention枚举成员之一。 The default value for the CallingConvention field is Winapi , which in turn defaults to StdCall convention. CallingConvention 字段的默认值是Winapi ,它反过来默认为StdCall约定。

I took your code, and played a little bit with it.我拿了你的代码,玩了一下。

code.cs :代码.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 :主.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

Notes :注意事项

  • I wasn't able to build it and run it in Excel , so I tried the 2 nd best thing: do it from VB .我无法构建它并在Excel 中运行它,所以我尝试了第二件最好的事情:从VB做它。 Note that I'm experienced in neither C# nor VB请注意,我对C#VB都没有经验
  • At the beginning (as I stated in a comment), I wasn't able to export anything from the C# .dll .一开始(正如我在评论中所述),我无法从C# .dll导出任何内容。 Looking at UnmanagedExports.nuspec (part of the nupkg ):查看UnmanagedExports.nuspecnupkg 的一部分):
    • You have to set your platform target to either x86, ia64 or x64.您必须将平台目标设置为 x86、ia64 或 x64。 AnyCPU assemblies cannot export functions. AnyCPU 程序集无法导出函数。
  • Changed the Platform from Any CPU ( VStudio default) to x64 (by mistake), and everything ran fine (in spite of CallingConvention.Cdecl ), only after setting it to x86 I was able to reproduce the problem平台Any CPUVStudio默认)更改为x64 (错误地),并且一切运行正常(尽管CallingConvention.Cdecl ),只有在将其设置为x86 后我才能重现该问题
  • Anyway, the ( C# ) code contains 3 ways of (not) specifying a calling convention, that will work from VB无论如何,( C# )代码包含 3 种(不)指定调用约定的方法,这将在VB 中工作

Output ( VStudio 2015 (Community) ):输出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

Here's an (ancient) URL that also mentions your error:[MSDN]: Bad DLL calling convention (Error 49)这是一个(古老的) URL ,也提到了您的错误:[MSDN]:错误的 DLL 调用约定(错误 49)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM