VBA调用同一C++动态链接库返回不同的结果

4

我有一个测试的dll函数,它会读取一个字符串并将其显示出来:

int _stdcall test(LPSTR myString) {
MessageBoxA(NULL, (LPCSTR)myString, "test", MB_OK);
return 0;}

Excel VBA声明为:

Declare Function test Lib "test.dll" (ByVal text As String) As Long

有一个子程序调用该函数。它读取一个值为“abcde”的Excel单元格,并能够显示正确的结果。该子程序代码如下:

sub testCode()
    test (cells(1,1).value)
end sub

然而,当使用Excel公式=test(A1)调用dll函数时,消息框只会显示字符串的第一个字符“a”。我花了整个周末阅读BSTR等内容,仍然不能解决这个问题。到底是怎么回事?
2个回答

2

Excel向您的C++代码传递一个BSTR。每个字符使用2个字节进行编码,第二个字节对于普通字符为0。这就解释了为什么您只看到第一个字符,因为MessageBoxA期望char*以null结尾的字符串。请使用

MessageBoxW

尝试使用此代码

int _stdcall test( const wchar_t * pString ) {
   MessageBoxW( NULL, pString, L"test", MB_OK ); // note the L prefix for literral
   return 0;
}

另一种方法是使用一些ATL宏或原始的Win32 API将BSTR指针转换为char*。比如WideCharToMultiByte(更加棘手,但使用ATL更简单)。


这是错误的。VB(A)在调用已声明的API时将字符串转换为当前系统代码页的ASCII。唯一不适用的情况是当API来自类型库时。然而,Excel可能会传递其他内容,但是直接将已声明的函数暴露给Excel表格引擎是我从未考虑过的事情。 - GSerg
@GSerg 你可能是对的,我是一个C++程序员,不是VBA程序员。但是当一个xxxA函数只显示第一个字符时,这是因为传递的指针是wchar_t类型的,而不是char类型的。 - manuell
你回答中唯一的“错误”是 VB pass。将其替换为 Excel pass 可能会使答案变得正确。 - GSerg
@GSerg 谢谢,我很感激。 - manuell
这里还有一些奇怪的问题:现在函数调用可以正确显示单词,但子程序现在显示了乱码特征。 我想把它作为我的周末功课 - 顺便问一下,是否有关于Excel VBA和dll的好参考书? - Allan D
@AllanD 我可以再次提供帮助,但我不理解你的新问题。请更新你现在使用的代码,并更清楚地解释哪里出了问题。 - manuell

2

将您导入的函数声明为私有函数:

Private Declare Function test_internal Lib "test.dll" Alias "test" (ByVal text As String) As Long

并创建一个Excel使用的包装函数:

Public Function Test (ByVal text As String) As Long
  Test = test_internal(text)
End Functin

显然,在调用Declare的API时,VB(A)将字符串参数转换为ASCII,使用当前系统代码页;但是Excel引擎不会这样做。

此外,您可能还希望删除括号


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