用在C++中创建的DLL从Excel和VBA调用C++函数

9
我创建了一个包含名为“koduj”的函数的DLL。在Excel工作表单元格中使用该函数调用会返回所需的结果。但是,从VBA调用“koduj”将返回错误的答案。
“koduj”需要两个参数:“string nr_id”和“integer x1”。它计算ASCII表示中nr_id的字母总和,并添加x1。然后返回计算出的总和。
我遵循了在这里找到的说明。
以下是我的.cpp源文件:
#include<Windows.h>
#include<string>
using namespace std;


//Convert BSTR to wstring for convenience
wstring BSTR_to_wstring (BSTR text){
    return wstring(text, SysStringLen(text));
}

//Calculate sum of letters in ASCII representation
int ASCII_sum (wstring ws){
    int sum = 0;
    for (unsigned int i = 0; i < ws.length(); i++)
        sum += ws[i];
    return sum;
}

//"koduj" function
int _stdcall koduj (BSTR nr_id, int & x1){
    wstring ws_nr_id = BSTR_to_wstring(nr_id);
    return ASCII_sum(ws_nr_id) + x1;
}

这是我的VBA函数声明:

Declare Function koduj _
Lib "<dll_directory_and_full_name>" (ByVal x As String, ByRef y As Integer) As Integer

通过编写:

=koduj("aaa";1)

在单元格内,我获得了期望的结果(292)。

调试这段VBA代码:

Sub test()

Dim a As Integer
a = koduj("aaa", 1)

End Sub

显示错误结果(a = 24930)

我相信我的C++代码没有问题,因为在从Excel的工作表中调用时它能正常工作。


尝试将a定义为Variant类型 - 你得到了相同的结果吗? - enderland
@enderland,没错,是相同的(错误)值。 - browning0
这对我来说很有趣。我在我的机器上复制了相同的问题,还注意到任何三个小写字符的koduj("***")返回相同的值。另请注意,如果您执行Debug.Print koduj("Ab", 1) - koduj("Aa", 1),您会得到256,这让我感到非常奇怪。 - enderland
4个回答

4
原因是尽管 VBA 字符串在内部是 UTF-16,但 VB 在与外界通信(Declare 函数、文件输入/输出)之前总是将它们转换为 ASCII。因此,当您声明一个参数 As String 时,VBA 会自动将字符串转换为 ASCII 并传递出去。C++ 端的匹配参数类型应该是 LPSTRLPCSTR
如果您想在 C++ 端使用 BSTR,还需要为该函数创建一个 IDL 文件,将其编译为 TLB,并从 VBA 引用 TLB,只有这样 VBA 才会尊重并使用 BSTR
另一个问题是 C++ 的 int 转换为 VBA 的 Long
当从 Excel 表格调用时,它能够工作的原因是显然 Excel 忽略了 VBA 的字符串转换规则。我认为这是一个 bug。

-1

这不是一篇完整的答案,但你的第二个参数类型似乎有误。

你的DLL函数: int _stdcall koduj (BSTR nr_id, int & x1) 声明了 x1 为一个(大概)32位整数的引用。

你的VBA声明: Declare Function koduj Lib "<dll_directory_and_full_name>" (ByVal x As String, ByRef y As Integer) As Integer 声明了y是指向一个16位整数的指针。

我建议您修改VBA声明如下:

Declare Function koduj _ Lib "<dll_directory_and_full_name>" (ByVal x As String, ByVal y As Long) As Long

并将您的DLL函数签名更改为按值传递x1:

int _stdcall koduj (BSTR nr_id, int x1)


是的,Integer/Long的情况就像您所描述的那样,应该进行修复。但这与字符串未作为bstr到达无关。 - GSerg

-1
从错误的大小来看,我猜测是数字参数出了问题 - 我建议在测试VBA例程中更明确地声明参数类型(可能是整数),并在C++端以该特定类型(在这种情况下为有符号短整型)接受它。
关于所有这些内容,有一篇很棒的微软文章,可以在http://msdn.microsoft.com/en-us/library/office/bb687915(v=office.15).aspx找到。

-1
尝试声明一个长整型变量a: Dim a As Long

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接