Как получить прямой доступ к переменным VARIANT в C ++? - PullRequest
0 голосов
/ 06 января 2020

Моя программа использует внешнюю библиотеку OCX и получает данные через нее. Приведенный ниже код показывает, как это работает.

    VARIANT    varArrItem, varArrData;

    ocx_instance.GetItemArr(real, &varArrItem);      // the library provides GetItemArr
                                                     // 1) receives data 
    long lLBound, lUBound;
    VARIANT varItem, varData;

    long index[2];
    index[0] = 0;
    index[1] = 0;

    COleSafeArray* pSafeItemArr = (COleSafeArray*)&varArrItem;    // 2) casts varArrItem to COleSafeArray
    CString strItem;
    CStringArray arrItem;

    pSafeItemArr->GetLBound(1, &lLBound);
    pSafeItemArr->GetUBound(1, &lUBound);

    int nItemCnt = (lUBound - lLBound + 1);
    for (int i = 0; i < nItemCnt; i++)
    {
        index[0] = i;
        VariantInit(&varItem);

        pSafeItemArr->GetElement(index, (void *)&varItem);    // 3) gets its values using GetElement
        strItem = varItem.bstrVal;
        arrItem.Add(strItem);

        VariantClear(&varItem);
    }

Большая проблема программы заключается в том, что этот код запускается всякий раз, когда поступают новые данные, что довольно часто и потребляет много ресурсов. Итак, я хотел бы упростить код и получить только содержимое varArrItem, например, в виде строк или массива структур строк.

varArrItem.vt дает мне 8204, и говорят, что оно состоит 8192(VT_ARRAY) и 12(VT_VARIANT). Я застрял здесь и не знаю, что делать после этого. Как я могу просто получить то, что в них? Можно ли получить к ним доступ без использования COleSafeArray?

1 Ответ

1 голос
/ 06 января 2020

Вам НЕ НУЖНО использовать COleSafeArray, это просто оболочка для удобства. Вы можете просто извлечь указатель SAFEARRAY* непосредственно из varArrItem и затем напрямую использовать API-интерфейсы SafeArray: SafeArrayGet(L|U)Bound(), SafeArrayGetElement() и т. Д. c, хотя, если важна производительность, рассмотрите возможность использования SafeArrayAccessData() для доступа к * Массив 1007 * напрямую, и, следовательно, его BSTR указатели. Чем меньше вы копируете данные, тем быстрее будет выполняться код. Единственная копия данных, которую этот код фактически должен сделать, - это присвоение начального VARIANT и каждого CString, добавляемого к CStringArray:

VARIANT varArray;
ocx_instance.GetItemArr(real, &varArray);

LPSAFEARRAY psa = varArrar.parray;

LONG lLBound, lUBound;
SafeArrayGetLBound(psa, 1, &lLBound);
SafeArrayGetUBound(psa, 1, &lUBound); 

CStringArray arrItem;

VARIANT *varArrayData;
if (SUCCEEDED(SafeArrayAccessData(psa, (void**) &varArrayData)))
{
    int nItemCnt = (lUBound - lLBound + 1);

    for (int i = 0; i < nItemCnt; i++)
    {
        CString strItem = varArrayData[i].bstrVal;
        arrItem.Add(strItem);
    }

    SafeArrayUnaccessData(psa);
}
...