COM: передать ссылку на SAFEARRAY

Вступление

Я хочу запросить функцию COM с помощью Qt. У меня есть документация, но для VB. Тем не менее этот документ говорит:

Object.Frequencies DataArray

Object     -> An object expression that evaluates to a BKDataSet object.
DataArray  -> An array of strings or an array of values

The DataArray structure must be declared in the application that is controlling PULSE and the size of the array must be equal to the number of x-axis entries. In Visual Basic, use the DIM (or corresponding) statement to declare the variable and allocate storage space. In other languages use a safearray of strings (VT_BSTR) or reals (VT_R8 for double or VT_R4 for float/single).


Шаг 1

Сначала я использовал OLEVIEW чтобы увидеть, как на самом деле выглядит прототип функции.

Я получил: void Frequencies(VARIANT* FrequencyArray),

Поэтому я попытался сделать это с помощью Qt:

IBKDataSet *data = function->FunctionData();
int nbFrequencies = data->dynamicCall("GetNumberOfXAxisEntries()").toInt();
QList<QVariant> frequencies;
for(int i=0; i<nbFrequencies; j++) {
frequencies << 0.0;
}
QList<QVariant> parameters;
parameters << QVariant(frequencies);
data->dynamicCall("Frequencies(QVariant&)", parameters);
for(int i=0; i<frequencies.size(); i++) {
qDebug() << frequencies.at(i);
}

Примечание: я использовал QList<QVariant> как показано Вот.

Но у меня было следующее сообщение Type Mismatch in Parameter. Pass an array of type string or real.,


Шаг 2

Поэтому я попытался с массивом строк:

IBKDataSet *data = function->FunctionData();
int nbFrequencies = data->dynamicCall("GetNumberOfXAxisEntries()").toInt();
QList<QString> frequencies;
for(int i=0; i<nbFrequencies; i++) {
frequencies << "0.0";
}
QList<QVariant> parameters;
parameters << QVariant(frequencies);
data->dynamicCall("Frequencies(QList<QString>&)", parameters);
for(int j=0; j<frequencies.size(); j++) {
qDebug() << frequencies.at(j);
}

Больше ошибок нет, но возвращаемые значения — это значения, установленные во время инициализации (я пробовал с несколькими, а не только с 0.0).


Шаг 3

После этого я попробовал много комбинаций, но безуспешно. Поэтому я попросил разработчиков (трудно связаться) привести пример. Мне прислали следующий код (Visual-C ++):

IBKDataSetPtr bkDataSet(function->FunctionData);
int nEntries = bkDataSet->GetNumberOfXAxisEntries();
COleSafeArray safeArray;

safeArray.CreateOneDim( VT_R8, nEntries);
COleVariant vDontCare;
bkDataSet->Frequencies(&safeArray);
double* pFrequencyData;
safeArray.AccessData((void**)&pFrequencyData);
CString sMessage;
sMessage.Format("Y[1] = %1.4e ", pFrequencyData[1]);
MessageBox(sMessage);
safeArray.UnaccessData();

Вопрос

Как этот код можно использовать в QtCreator?

Я реализовал COleSafeArray специфично для VisualStudio …

Прошу прощения за длину поста, но сейчас я пытаюсь обойти эту проблему без успеха.


РЕДАКТИРОВАТЬ

Вот подсказка о том, как это сделать с помощью WIN32 API:

QList<double> getCOMValues(IDispatch *dispatch, const QString &method, int arraySize) const {
QList<double> result;
HRESULT hr;
// I don't know how to convert a QString into an OLECHAR*
OLECHAR * szMember = L"Frequencies";
DISPID dispid;

// Retrieve the dispatch identifier for the method.
// Use defaults where possible.
hr = dispatch->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_USER_DEFAULT, &dispid);

// Test return is OK
if(FAILED(hr)) {
qDebug() << "Error while trying to read the " << method;
return result;
}

// Defines a SAFEARRAY.
SAFEARRAY *psa;
// Represents the bounds of one dimension of the array.
SAFEARRAYBOUND freqBound[1];
// The lower bound of the dimension starts at 0.
freqBound[0].lLbound = 0;
// The number of elements in the dimension is the number of frequencies.
freqBound[0].cElements = arraySize;

// Creates a new array descriptor, allocates and initializes the data for
// the array, and returns a pointer to the new array descriptor.
// VT_R8 represents double.
// 1 is the number of dimensions in the array.
psa = SafeArrayCreate(VT_R8, 1, freqBound);

// Check the array is not NULL.
if(psa == NULL) {
qDebug() << "Error while trying to read the " << method;
return result;
}

// This is the default value to put into the array.
double init[] = {0.0};
// Populates the array with 0.0.
for(long index=0;index<arraySize;index++)
{
// Stores the data element at the specified location in the array.
hr = SafeArrayPutElement(psa,&index,init);
if( FAILED(hr)) {
qDebug() << "Error while initialising the array for " << method;
}
}

// Describes arguments passed within DISPPARAMS.
VARIANTARG v[1];
// A safe array descriptor, which describes the dimensions, size, and in-memory location of the array.
v[0].parray = psa;
// The type of data in the union.
v[0].vt = VT_ARRAY|VT_R8;

// Contains the arguments passed to a method or property.
DISPPARAMS params = {v, NULL, 1, 0};

// To catch errors
EXCEPINFO pExcepInfo;

// Provides access to properties and methods exposed by the object.
hr = dispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, &pExcepInfo, NULL);

if(FAILED(hr)) {
if(hr == DISP_E_EXCEPTION) {
printf("%S\n", pExcepInfo.bstrSource);
printf("%S\n", pExcepInfo.bstrDescription);
}

qDebug() << "Error while trying to read the " << method;
return result;
}

double res = 0;
for(long idx=0; idx<arraySize; idx++) {
hr = SafeArrayGetElement(psa, &idx, &res);
if(hr == S_OK) {
result.push_back(res);
} else {
result.push_back(0.0);
qDebug() << "Error while trying to read the " << method;
}
}

// Clears the variant.
hr = VariantClear(v);

return result;
}

Но Invoke метод возвращает DISP_E_EXCEPTION: Type Mismatch in Parameter. Pass an array of type string or real.

0

Решение

Нашел проблему. Очень просто!

IBKDataSet *data = function->FunctionData();
int nbFrequencies = data->dynamicCall("GetNumberOfXAxisEntries()").toInt();
QList<QString> frequencies;
for(int i=0; i<nbFrequencies; i++) {
frequencies << "0.0";
}
QList<QVariant> parameters;
parameters << QVariant(frequencies);
data->dynamicCall("Frequencies(QList<QString>&)", parameters);
frequencies = parameters.first().toStringList();
for(int j=0; j<frequencies.size(); j++) {
qDebug() << frequencies.at(j);
}

Я должен был прочитать первый элемент parameters и преобразовать его в QStringList

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]