Я пишу C ++ DLL для доступа из Excel VBA (она только дополняет математические уравнения и не требует доступа к рабочему листу). DLL предназначена для замены текущего кода VBA, и я хочу написать его на C / C ++ для повышения производительности.
Поскольку я использую существующий код и просто хочу заменить текущую функцию VBA новой DLL, я должен использовать варианты VBA, содержащие одиночные векторные массивы. Ниже приведен сокращенный пример кода вызова VBA:
Sub VBACaller()
Dim InputR0(1 To 5) As Variant, vResult As Variant
InputR0(1) = 26.8
InputR0(2) = 27.8
InputR0(3) = 28.8
InputR0(4) = 29.8
vResult = ReadArrayVBA(InputR0)
End Sub
Я могу передать этот массив Variant моей функции C ++ либо ByVal
или же ByRef
как VARIANT
Тип данных, и он, кажется, был получен правильно. Мои проблемы возникают, когда я пытаюсь прочитать содержимое массива после преобразования его в SAFEARRAY
с помощью SafeArrayAccessData
, SAFEARRAY
кажется, что преобразование работает, но содержимое массива неверно. Вот мой код на C ++:
VARIANT __stdcall ReadArrayByRef(VARIANT *input0)
{
//Variable to assign value from Array
double d_m = 0;
//Check if this is a variant type or not
if (V_VT(input0) & VT_ARRAY)
{
SAFEARRAY* pSafeArrayInput0 = NULL;
pSafeArrayInput0 = V_ARRAY(input0);
double* pVals;
HRESULT hr = SafeArrayAccessData(pSafeArrayInput0, (void **)&pVals); // direct access to SA memory
if (SUCCEEDED(hr))
{
long lLBound = -1, lUBound = 1; // get array bounds
SafeArrayGetLBound(pSafeArrayInput0, 1, &lLBound);
SafeArrayGetUBound(pSafeArrayInput0, 1, &lUBound);
if (lLBound > -1 && lUBound > -1)
{
d_m = pVals[1];
}
SafeArrayUnaccessData(pSafeArrayInput0);
}
}
//Output
VARIANT v;
VariantInit(&v);
v.vt = VT_R8;
v.dblVal = d_m;
return v;
}
Примеры, которые я нашел, показывают, что .parray
должны содержать данные, однако осмотр input0
указывает, что это в .pparray
, Если я попытаюсь назначить pSafeArrayInput0 = input0.pparray
это дает ошибку. Значение d_m
возвращается по линии 1.05319234616515E-307
,
Если я изменю ввод на ByVal
тогда я могу получить доступ к элементам массива правильно, используя следующий код C ++ (единственное отличие состоит в том, что адрес input0 доступен через SAFEARRAY
,
VARIANT __stdcall ReadArrayByVal(VARIANT input0)
{
//Variable to assign value from Array
double d_m = 0;
//Check if this is a variant type or not
if (V_VT(&input0) & VT_ARRAY)
{
SAFEARRAY* pSafeArrayInput0 = NULL;
pSafeArrayInput0 = V_ARRAY(&input0);
double* pVals;
HRESULT hr = SafeArrayAccessData(pSafeArrayInput0, (void **)&pVals); // direct access to SA memory
if (SUCCEEDED(hr))
{
long lLBound = -1, lUBound = 1; // get array bounds
SafeArrayGetLBound(pSafeArrayInput0, 1, &lLBound);
SafeArrayGetUBound(pSafeArrayInput0, 1, &lUBound);
if (lLBound > -1 && lUBound > -1)
{
d_m = pVals[1];
}
SafeArrayUnaccessData(pSafeArrayInput0);
}
}
VARIANT v;
VariantInit(&v);
v.vt = VT_R8;
v.dblVal = d_m;
return v;
}
Все примеры, которые я нашел, показывают, что прохождение VARIANT
ввод с помощью указателя должен работать для моей функции ReadArrayByRef (т.е. http://support.microsoft.com/kb/167668 что немного отличается, но то же самое в точках, которые я после).
Что я делаю не так в своей функции ByRef?
Вы должны проверить VT_BYREF
флаг, и если он установлен, разыменуйте указатель для доступа к массиву следующим образом:
pSafeArrayInput0 = *V_ARRAYREF(input0);
Других решений пока нет …