这将是一篇很长的帖子,但我不确定需要哪些信息来正确解释这个问题。我有一个C ++ DLL,我试图从Excel调用。其中一个函数导致Excel在我调用它时“Microsoft Excel已停止工作”崩溃。
标题文件:
#include <string>
namespace XYZ_ProjectWise
{
class FileOperator
{
public:
static __declspec(dllexport) long __stdcall initialize(std::string dbName);
static __declspec(dllexport) long __stdcall openDoc(long projectID,long docID);
};
}
initialize()
的功能代码:
long FileOperator::initialize(string dbName)
{
LPCWSTR user=L"";
LPCWSTR pwd=L"";
LPCWSTR schema=L"";
std::wstring sTemp=std::wstring(dbName.begin(),dbName.end());
LPCWSTR dbName_L=sTemp.c_str();
bool resultInit=aaApi_Initialize(AAMODULE_ALL);
bool resultLogin=aaApi_Login(AAAPIDB_UNKNOWN,dbName_L,user,pwd,schema);
return 0;
}
dumpbin / exports的输出:
?initialize@FileOperator@XYZ_ProjectWise@@SGJV?$basic_string@DU?$char_traits@D@std@@V?
$allocator@D@2@@std@@@Z
VBA宣言:
Private Declare Function initialize Lib "C:\Program Files
(x86)\Bentley\ProjectWise\bin\XYZ_ProjectWiseDLL.dll" _
Alias "?initialize@FileOperator@XYZ_ProjectWise@@SGJV?$basic_string@DU?
$char_traits@D@std@@V?$allocator@D@2@@std@@@Z" _
(ByVal dbName As String) As Long
如何在VBA中调用它:
Public Sub testDLL()
Dim result As Long
result = initialize("ABC.DEF.GHI.com:PWOPPID_XYZ")
End Sub
如果我在initialize()
函数中包含openDoc()
函数代码,并dbName
进行了硬编码,并且自己调用openDoc()
,则不会发生崩溃。如下:
long __stdcall FileOperator::openDoc(long projectID,long docID)
{
LPCWSTR dbName=L"ABC.DEF.GHI.com:PWOPPID_XYZ";
LPCWSTR user=L"";
LPCWSTR pwd=L"";
LPCWSTR schema=L"";
bool resultInit=aaApi_Initialize(AAMODULE_ALL);
bool resultLogin=aaApi_Login(AAAPIDB_UNKNOWN,dbName,user,pwd,schema);
long resultOpen=aaApi_OpenDocument(projectID,docID,false);
return resultOpen;
}
}
VBA电话:
Private Declare Function openDoc Lib "C:\Program Files
(x86)\Bentley\ProjectWise\bin\XYZ_ProjectWiseDLL.dll" _
Alias "?openDoc@FileOperator@XYZ_ProjectWise@@SGJJJ@Z" _
(ByVal projectID As Long, ByVal docID As Long) As Long
Public Sub testDLL()
Dim result As Long
result = openDoc(1799,29)
End Sub
那么为什么VBA调用initialize()
会崩溃,但是对openDoc()
的VBA调用中的相同代码工作得很好?
答案 0 :(得分:3)
显而易见的问题是C ++代码使用的C ++类对interop无效。 VBA编组器根本无法提供std :: string。只使用简单的POD类型进行互操作。
在C ++方面,对于字符串参数,接收指向空终止字符数组的指针const char *。由于std :: string有一个接受const char *的构造函数,因此很容易根据需要调整这样的参数。
在VBA端,您通过值字符串声明字符串参数,并且VBA编组器将转换为char *。您已经这样做,因此您需要的唯一更改是在C ++代码中。