I have this problem for a long time, any help would be very appreciated! I am writing a C++ DLL used in VBA. While when I try to return a VARIANT (contain a SafeArry of BSTR) back to VBA and using this return value to fill the cells in excel, the cells are filled with correct values but I have Run-time error 10: This array is fixed or temporarily locked.
The idea is to pass a 2d matrix from excel to DLL to do some filtration and then pass the result back to Excel. As ScreenShot below, here I want to only keep people with "Active" Status:
I am wondering do I need to destroy the variant (varOut in my code)? how should I do that?
Or I have wrong declaration in VBA? What puzzled me is I can still fill right values to the cells in Excel but in the meantime, I have the run-time error.
My VBA Definition is as follow:
Declare Function PrepareData Lib "C:\dll_path" (source As Variant) As Variant
Sub test()
Dim input, result As Range
Set input = Range("A1:C4")
Set result = Range("A6:C6")
result.value = PrepareData(input.value)
And my C++ Code is as below:
VARIANT __stdcall PrepareData(VARIANT* sourceRange) {
// Convert VBA Range to 2d Vector
vector<vector<string>> sourceArray = VBARangeToArray(sourceRange);
// Do filteration
vector<vector<string>> outputArray = FilterData(sourceArray);
// Convert 2d Vector back to VBA Variant
VARIANT outputRange = ArrayToVBARange(outputArray);
return outputRange;}
VARIANT ArrayToVBARange(vector<vector<string>> Array) {
int nrows = Array.size();
int ncols = Array[0].size();
int cnt_elements = nrows * ncols;
// Construct new SafeArray
BSTR *ptrArray = NULL;
SAFEARRAYBOUND rgsabound[2];
rgsabound[0].lLbound = 1;
rgsabound[0].cElements = nrows;
rgsabound[1].lLbound = 1;
rgsabound[1].cElements = ncols;
SAFEARRAY* pStringArray = SafeArrayCreate(VT_BSTR, 2, rgsabound);
HRESULT hr = SafeArrayAccessData(pStringArray, (void**)&ptrArray);
// Fill the SafeArray
for (int i = 0; i < cnt_elements; i++) {
int Row = i % nrows;
int Col = i / nrows;
_bstr_t tmp(Array[Row][Col].c_str());
ptrArray[i] = tmp.copy();
}
SafeArrayUnaccessData(pStringArray);
// Constrcut the return variable, type: Variant
VARIANT varOut;
VariantInit(&varOut);
varOut.vt = VT_ARRAY | VT_BSTR;
varOut.parray = pStringArray;
return varOut;}