我正在使用Visual C ++ 2012来创建一个包装函数,用于从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
我通过设置调试器将其缩小到API调用,以便在VBA调用selectFile()
后它进入C ++代码。我通过将EXCEL.EXE设置为Debugging-> Command和C / C ++ - >浏览信息 - >启用浏览信息设置为“是(/ FR)”来完成此操作。
令人费解的是,从VBA调用时,函数的唯一元素(或看起来不同)是docArray
参数,selectFile()
甚至不会被aaApi_DocumentSelectDlg()
使用。 API调用。当我到达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).
行并进入它时,我收到以下错误消息:
docArray
为什么VBA会导致此堆损坏?我正在传递指向aaApi_DocumentSelectDlg()
的第一个元素的指针,这样我就可以将数组从VBA传递给DLL函数,而不必使用SAFEARRAY,但我不认为这是问题,因为调用{ {1}}不使用docArray
。
编辑:我制作了另一个版本的selectFile()
,它不接受任何参数,以测试错误是否在没有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;
}
}
答案 0 :(得分: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
这显式地向函数发送数组的第一个元素的地址。
答案 1 :(得分:0)
由于您将Longs的数组传递给您的DLL调用,看起来它被调用改变了,我猜它应该通过地址传递。
声明(ByVal lpdocArray As Long)
传递32位值的内容。
我认为你用ByRef而不是ByVal会更好 - 然后会自动传递地址。
既然你已经使用了ByRef,你应该能够使用变量标识符进行调用:
result = selectFile(docArray)