VBA运行声明函数时堆损坏,但C ++控制台应用程序运行正常吗?

我正在使用Visual C ++ 2012来创build一个包装函数从VBA进行API调用。 如果它很重要,这是为Bentley ProjectWise API,我打电话给aaApi_DocumentSelectDlg()

当我从C ++控制台应用程序运行这个函数时,这个函数起作用,但是当我从VBA调用它并遍历函数时,API调用会导致堆损坏错误。

这是包装函数:

 //function for opening a file select dialog and getting the IDs associated with //that file long __stdcall FileOperator::selectFile(long* docArray) { try { //set parameters for dialog AAOPENDOCSDLG2_PARAM param={0}; param.ulMask |= AAOPENDLG2_MASK_FLAGS|AAOPENDLG2_MASK_TITLE|AAOPENDLG2_MASK_PROJECTID| AAOPENDLG2_MASK_DOCUMENTID|AAOPENDLG2_MASK_FILENAME; param.ulFlags = AAOPENDLG2_SINGLE_SELECTION | AAOPENDLG2_GET_IDS_ONLY | AAOPENDLG2_HIDEREADONLY | AAOPENDLG2_NO_USE_LASTPROJ; param.lpctstrTitle = L"Select a file"; //open dialog, get result of user's selection long result=aaApi_DocumentSelectDlg(&param); //set array values to pass file info out of function if(result==IDOK) { docArray[0]=param.plProjectIds[0]; docArray[1]=param.plDocumentIds[0]; } else { docArray[0]=0; docArray[1]=0; } return 1; } catch (exception& e) { //error string not returned, just used for debugging string error=e.what(); return 0; } } 

以下是成功执行的控制台应用程序:

 int main() { //initialization function for opening session with database. no problem here. long initResult=TestDLL::FileOperator::initialize("Test.QA.com:PWOPPID_XYZ"); long selectResultArray[2]={0}; TestDLL::FileOperator::selectFile(selectResultArray); return 0; } 

以下是导致堆损坏的VBA代码:

 Private Declare Function selectFile _ Lib "C:\Program Files (x86)\Bentley\ProjectWise\bin\TestDLL.dll" _ Alias "?selectFile@FileOperator@TestDLL@@SGJPAJ@Z" _ (ByRef docArray As Long) As Long Public Function selectPWFolder() As Long Dim docArray(1) As Long Dim result As Long docArray(0) = 0 docArray(1) = 0 result = selectFile(docArray(LBound(docArray))) selectPWFolder = docArray(1) End Function 

我已经通过设置debugging器将其缩小到API调用,以便一旦VBA调用selectFile() ,它就进入C ++代码。 我通过设置EXCEL.EXE作为debugging – >命令,和C / C ++ – >浏览信息 – >启用浏览信息设置为“是(/ FR)”。

令人费解的是,从VBA中调用的函数的唯一元素(或者看起来)是docArray参数,直到API调用之后selectFile()使用。 当我到达aaApi_DocumentSelectDlg()行并进入它,我得到以下错误信息:

 Critical error detected c0000374 EXCEL.EXE has triggered a breakpoint. First-chance exception at 0x77E0E753 (ntdll.dll) in EXCEL.EXE: 0xC0000374: A heap has been corrupted (parameters: 0x77E44270). 

为什么VBA会导致这个堆腐败? 我传递一个指向docArray的第一个元素的指针,以便我可以将数组从VBA传递到DLL函数,而不必使用SAFEARRAY,但是我不认为这是问题,因为调用aaApi_DocumentSelectDlg()使用docArray

编辑:我做了另一个版本的selectFile() ,不接受任何参数,以testing是否发生没有docArray的错误。 堆损坏错误仍然发生。 所以它与API调用本身有关,与传递数组无关。

初始化函数的代码是:

 long FileOperator::initialize(char* dbName) { LPCWSTR user=L""; LPCWSTR pwd=L""; LPCWSTR schema=L""; std::string dbNameStr=std::string(dbName); std::wstring sTemp=std::wstring(dbNameStr.begin(),dbNameStr.end()); LPCWSTR dbName_L=sTemp.c_str(); bool resultInit=aaApi_Initialize(AAMODULE_ALL); bool resultLogin=aaApi_Login(AAAPIDB_UNKNOWN,dbName_L,user,pwd,schema); if (resultInit&&resultLogin) { return 11; } else if (resultInit&&!resultLogin) { return 10; } else if ((!resultInit)&&resultLogin) { return 1; } else { return 0; } } 

尝试将您的VBA更改为:

 Private Declare Function selectFile _ Lib "C:\Program Files (x86)\Bentley\ProjectWise\bin\TestDLL.dll" _ Alias "?selectFile@FileOperator@TestDLL@@SGJPAJ@Z" _ (ByVal lpdocArray As Long) As Long Public Function selectPWFolder() As Long Dim docArray(1) As Long Dim result As Long docArray(0) = 0 docArray(1) = 0 result = selectFile(VarPtr(docArray(0))) selectPWFolder = docArray(1) End Function 

这明确地发送函数数组的第一个元素的地址。

由于你正在传递一个Long 数组给你的DLL调用,看起来它正在被调用改变,我猜它应该通过地址传递。
声明(ByVal lpdocArray As Long)传递一个32位值的内容。 我觉得你最好用ByRef而不是ByVal – 然后自动传递地址。

现在,由于您已经使用了ByRef,您应该可以使用variables标识符来调用:
result = selectFile(docArray)