我在C / C ++中编写一个dll,用于从vba中使用,处理双精度数组。在vba中,一个双精度数组内部映射到LPSAFEARRAY结构,这可以传递给C ++。但是也可以在Variant参数中传递它:可以说LPSAFEARRAY包含在Variant参数中。 因为Excel范围也可以在Variant中传递,我编写一个C ++函数,将VARIANT作为参数并生成LPSAFEARRAY,以便在C ++中进一步处理。我的尝试,功能mat(),没有任何检查,是:
VARIANT getdata(VARIANT & ExcelArray) {
VARIANT dvout; EXCEPINFO excep; DISPPARAMS dispparams; unsigned int uiArgErr; DISPID dispidValue;
LPOLESTR XName = L"Value2";
ExcelArray.pdispVal->GetIDsOfNames(IID_NULL, &XName, 1, LOCALE_SYSTEM_DEFAULT, &dispidValue);
dispparams.cArgs = 0;
dispparams.cNamedArgs = 0;
ExcelArray.pdispVal->Invoke(dispidValue, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dispparams, &dvout, &excep, &uiArgErr);
ExcelArray.pdispVal->Release();
return dvout;
}
inline LPSAFEARRAY getarray (VARIANT const &var) {
// Extract the array (differs if it came in by reference)
if (var.vt & VT_BYREF)
return * var.pparray;
else
return var.parray;
}
xll_LPSAFEARRAY mat (VARIANT & src) {
if (src.vt == VT_DISPATCH) // if range, convert it
src = getdata(src);
if (src.vt == VT_R8) { // a single value
vbMatrix<double> A(1, 1);
A[1] = src.dblVal;
return A;
}
else if ((src.vt & VT_VARIANT) != 0) {
vbMatrix<VARIANT> v(&src.parray);
vbMatrix<double> A(v.rows, v.cols);
for (int j = 1; j <= v.cols; j++)
for (int i = 1; i <= v.rows; i++)
A(i, j) = v(i, j).dblVal;
return A;
}
else {
LPSAFEARRAY a = getarray(src);
return a;
}
}
vba mat中的位置声明为
Declare PtrSafe Function mat Lib "lib.dll" (v) As Double()
现在,范围转换部分正常工作(即通过范围一切都很好)。但最简单的部分,即最后两行,当参数是double数组时调用,只会崩溃Excel。这让我很疯狂,因为底层LPSAFEARRAY的引用必须在Variant中。例如,在vba中,这可以工作:
Dim x() As Double, y() as Double, v as Variant
x = mat([A]) ' array of doubles
v = x ' out in a Variant
y = v ' copy to another array of double (= MAKES A COPY)
当然在C ++中也是可能的,但是我需要对原始数组的引用,而不是它的副本。 任何解决方案都表示赞赏。