COM:将引用传递给安全数组

COM: pass reference to a SAFEARRAY

本文关键字:安全 数组 引用 COM      更新时间:2023-10-16

简介

我想用Qt查询一个COM函数。我有一个文档,但用于 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

之后,我尝试了许多组合,但没有成功。所以我要求开发人员(很难联系(提供一个例子。他们向我发送了以下代码(可视化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("%Sn", pExcepInfo.bstrSource);
            printf("%Sn", 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.

发现问题。很简单!

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......