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(¶m); //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)