【问题标题】:"Bad DLL calling convention" while using a C++ dll from Excel VBA - How to resolve?使用 Excel VBA 中的 C++ dll 时出现“错误的 DLL 调用约定” - 如何解决?
【发布时间】:2019-02-21 00:55:16
【问题描述】:

我需要创建一个 C++ dll,它具有一个函数,该函数返回要在 Excel (2010) VBA 代码中使用的字符串。

我已经阅读了以下帖子:Using C++ DLL in Excel VBA - 以及 Microsoft 关于 C++ dll 创建和 VBA 使用的教程(Walkthrough: Create and use your own Dynamic Link Library (C++)Access DLLs in Excel)并按照程序进行操作。

代码如下:

C++ dll(取自微软网页):

// MathLibrary.h - Contains declarations of math functions
#pragma once

#ifdef MATHLIBRARY_EXPORTS
#define MATHLIBRARY_API __declspec(dllexport)
#else
#define MATHLIBRARY_API __declspec(dllimport)
#endif

// The Fibonacci recurrence relation describes a sequence F
// where F(n) is { n = 0, a
//               { n = 1, b
//               { n > 1, F(n-2) + F(n-1)
// for some initial integral values a and b.
// If the sequence is initialized F(0) = 1, F(1) = 1,
// then this relation produces the well-known Fibonacci
// sequence: 1, 1, 2, 3, 5, 8, 13, 21, 34, ...

// Initialize a Fibonacci relation sequence
// such that F(0) = a, F(1) = b.
// This function must be called before any other function.
extern "C" MATHLIBRARY_API void fibonacci_init(
    const unsigned int a, const unsigned int b);

// Produce the next value in the sequence.
// Returns true on success and updates current value and index;
// false on overflow, leaves current value and index unchanged.
extern "C" MATHLIBRARY_API bool fibonacci_next();

// Get the current value in the sequence.
extern "C" MATHLIBRARY_API unsigned int fibonacci_current();

// Get the position of the current value in the sequence.
extern "C" MATHLIBRARY_API unsigned fibonacci_index();

VBA 代码(我的,遵循 Microsoft 文档):

Public Declare Sub fibonacci_init Lib "C:\development\MathLibrary\Release\MathLibrary.dll" (ByVal a As Integer, ByVal a As Integer)
Public Declare Function fibonacci_next Lib "C:\development\MathLibrary\Release\MathLibrary.dll" () As Boolean
Public Declare Function fibonacci_current Lib "C:\development\MathLibrary\Release\MathLibrary.dll" () As Integer

Public Function run_dll()
    Dim b As Integer

    Call fibonacci_init(1, 1)
    b = fibonacci_current()
End Function

当我在 VBA 中运行 run_dll 函数时,我得到一个异常:Call fibonacci_init(1,1) 行上的“错误的 DLL 调用约定”。

这里有什么问题?我已经将 C++ 函数声明为extern "C",所以我假设调用约定是固定的......

更新

我尝试过的更多东西......

  1. 我按照 cmets/answers 中的提示从头开始创建了一个新的 dll:

试用.cpp:

const char* str = "abcdefg";

extern "C" __declspec(dllexport) int size()
{
    return strlen(str);
}

extern "C" __declspec(dllexport) bool test(char* pReturn)
{
    int nSize = strlen(str);
    lstrcpynA(pReturn, str, nSize);

    return true;
}

使用以下 VBA:

Public Declare Function size Lib "C:\development\MathLibrary\Release\Trial.dll" () As Long
Public Declare Function test Lib "C:\development\MathLibrary\Release\Trial.dll" (ByVal p As Long) As Boolean

(1) Public Function run_dll()
(2)    Dim bb As Boolean
(3)    Dim sz As Integer
(4)    Dim s As String        
(5)    sz = size()       
(6)    s = Space(sz)        
(7)    bb = test(StrPtr(s))
(8) End Function

第 5 行工作正常 - sz 收到 7。但第 7 行给出“错误的 DLL 调用约定”。

  1. 尝试使用 WINAPI 声明 C++ 函数,正如我在一篇文章中提到的那样,给出:Can't find DLL entry point size in C:\development\MathLibrary\Release\Trial.dll

  2. test VBA 声明更改为

Public Declare Function test Lib "C:\development\MathLibrary\Release\Trial.dll" (ByRef p As String) As Boolean

并以bb = test(s) 调用 (line7) - 导致 Excel 崩溃

  1. test VBA 声明更改为

Public Declare Function test Lib "C:\development\MathLibrary\Release\Trial.dll" (ByRef p As Long) As Boolean

并以bb = test(StrPtr(s)) 的形式调用 (line7) - 给出:“错误的 DLL 调用约定”

似乎没有任何工作。有人有这种设置的工作示例吗?

【问题讨论】:

  • @AlanBirtles:这篇文章谈到了 MSAccess VBA - 我没有关注那里的细节......我没有“VBA 编译器模块”
  • 最佳答案是关于 excel 的,其他几个也是如此
  • @AlanBirtles:它谈到了重新编译 Excel 加载项......而不是 C++ dll
  • 是的,对您的 excel 代码进行更改以使其重新编译,因为它有 24 个赞成票,并带有与您相同的错误消息,我想它很有可能会起作用

标签: c++ excel vba dll


【解决方案1】:

C++ 整数的等价物是一个长 VBA。

VBA 中的 Integer 是 2 字节数据类型,VBA 中的 Long 是 4 字节数据类型。由于传递的字节数与预期的字节数不匹配,您会得到一个错误的 DLL 调用约定

请注意,VBA 不支持无符号类型,因此您的输出会被解释为带符号的 4 字节整数(长整数)。

【讨论】:

  • 尝试将 VBA 声明更改为 (ByRef a As Long, ByRef b As Long) 并将 C++ 更改为 extern "C" __declspec(dllexport) void fibonacci_init(int a, int b); - 还是一样...
  • ByVal 不是ByRef!!你为什么要改变它?
  • 感谢您的帮助 - 但即使使用 ByVal 我仍然收到错误消息。可以要求您发布一些有效的代码(简单而简短)吗?
  • 不幸的是,我无法访问当前工作区中的 C++ 编译器,因此无法编译 DLL。但是 afaik 你应该刚刚改变了你的 VBA 代码。在 VBA 中使用有符号类型很常见,而实际上应该使用无符号类型。我认为在您的 C++ 代码中删除 Const 会导致这不起作用。我确实有代码来转换应该是无符号但被签名为双精度的长整数来解释更大的值。
【解决方案2】:

您需要将其设为 COM 库。一旦它们在 Windows 注册表中注册,就可以将它们导入到 VBA 代码中。

【讨论】:

  • 我想避免在正在运行的 windows 机器上注册 - 我想将 dll 部署为我的 excel 包的一部分 - 有没有 COM 和注册的选项?
猜你喜欢
  • 1970-01-01
  • 2017-04-19
  • 1970-01-01
  • 2010-10-09
  • 1970-01-01
  • 1970-01-01
  • 2016-06-10
  • 2011-09-14
  • 1970-01-01
相关资源
最近更新 更多