我正在使用Code::Blocks在C中编写一个DLL,我打算在Winbatch脚本中使用它,但目前我正在使用Excel VBA测试它。
VBA脚本运行DLL getVersion()函数Excel时崩溃。在网上搜索了几天:我没有找到合适的解决方案。
C代码是这样的
#define MQTTPUB_VERSION "V3.1.1Test"
DLL_EXPORT BSTR __stdcall WINAPI getVersion(void)
{
return MQTTPUB_VERSION ;
}
VBA代码如下
Public Declare Function mqttPubMsg Lib "mqttPubMsg.dll" _
(ByVal MQTT_ADDRESS As String, ByVal MQTT_CLIENTID As String, ByVal MQTT_TOPIC As String, ByVal MQTT_PAYLOAD As String) As Long
Public Declare Function getVersion Lib "mqttPubMsg.dll" () As String
Sub Test_DDL_mqttPubMsg()
'
' to test mqttPubMsg.DLL used in Visual Basic (VBA)
'
Dim DLLVersion As String * 35
Dim WorkDir As String
DLLVersion = Space(35)
WorkDir = ThisWorkbook.Path
ChDir WorkDir
If Dir(WorkDir & "\mqttPubMsg.dll", vbDirectory) = vbNullString Then
MsgBox "DLL not found"
Else
On Error GoTo DLLError
DLLVersion = getVersion() 'Excel crashes on executing this statement
End If
MsgBox ("Version DDL: " & DLLVersion)
Exit Sub
DLLError:
MsgBox ("DDL error")
End Sub
调用DLL和getVersion()函数的C程序可以正常工作。
运行时错误的原因和解决方法。
提前谢谢。
最佳答案
我最近没有做过Windows编程,也没有现成的开发环境来进行实验,但是这里有一些想法。
这里最可能的问题是getVersion()
返回BSTR
,这也是(可能)当返回类型声明为String
时调用VBA代码所期望的。现在,BSTR
应该在内存中前面加上一个4字节长度的前缀,请参见https://msdn.microsoft.com/en-us/library/windows/desktop/ms221069%28v=vs.85%29.aspx。getVersion()
只返回一个指向字符串第一个字符“V”的指针,当VBA试图将“V”之前的4个字节解释为长度时,这是一个灾难。。。
以下是我看到的一些可能的解决方案:
使用中的BSTR
函数构造SysAllocString()
getVersion()
如上述参考文章中所推荐。
通过引用将DLLVersion
字符串传递给getVersion()
,并查看
如果你能在getVersion()
中填充它。记住这一点
你正在处理Unicode。
出于好奇,还可以玩一些其他的东西:
验证是否可以从VBA实际调用DLL函数;让getVersion()
返回void并查看是否只调用该函数
崩溃Excel。如果是这样,那么问题就更严重了。
使getVersion()
返回一个整数并查看是否可以将其输入
你的VBA代码。
使getVersion()
接受一个整数作为参数,并将其传递给
整数,看看C代码是否能得到正确的值。
在C代码中有足够大的全局字符数组,将
(Unicode!)从数组中偏移量4开始的版本字符串,以及
用一个整数(我认为是小尾数)填充前4个字节
指示Unicode字符串的长度(不包括空值)
终结者。使getVersion()
返回指向buf + 4
的指针,
其中buf
是全局字符数组。
很抱歉,我的记忆不新鲜,我不能提供更具体的建议,但希望这有帮助。