How to correct use SAFEARRAY of Variants in C++/CLI

408 Views Asked by At

I have an array of variant data that I need to acquire on the native side and then marshall into the managed size. Some members of the array are themselves an array so I'm trying to populate these items as a variant of safearray. I'm using C++/CLI and trying to stick to using types _variant_t and SAFEARRAY* i.e. I'm trying to avoid using ATL/CComSafeArray.

If the _variant_t is a primitive, then get_data has the correct value and Marshal::GetObjectsForNativeVariants marshals it correctly. However, this call fails for variants which contain SAFEARRAYs because the contents of the them do not contain the correct data which leads to an Access Violation. It seems that the memory is getting destroyed somewhere and I can't figure out why / what I am doing wrong:

memory contents

Any help would be greatly appreciated! (I'm stuck)

Here's the code:

C++/CLI

List<object> values;
_variant_t nativeValueArray[64] = {};

// simplified this line below just to illustrate the problem...
ItemType nativeTypeArray[64] = { ItemType::ARRAY };

auto result = get_data(64, nativeTypeArray, nativeValueArray);
auto data = Marshal::GetObjectsForNativeVariants(IntPtr((void*)nativeValueArray), 64);
values = gcnew List<object>(data);

C++

enum class ItemType
{
   ARRAY, PRIMITIVE
};

SAFEARRAY* StoreSafeArray(const std::vector< _variant_t > &values, VARENUM type)
{
    // allocate the safe array itself
    auto sa = SafeArrayCreateVector((VARTYPE)type, 0, values.size());
    if (sa == nullptr)
    {
        // error handling
    }

    _variant_t* ptr;
    if (FAILED(SafeArrayAccessData(sa, (void**)&ptr)))
    {
        // error handling
    }

    for (LONG idx = 0; idx < (LONG)values.size(); idx++)
    {
        ptr[idx] = values[idx];
    }

    if (FAILED(SafeArrayUnaccessData(sa)))
    {
        // error handling
    }

    return sa;
}

_variant_t populateVariantSafeArray(const std::vector< _variant_t> &values)
{
    SAFEARRAY* sa = nullptr;

    // copy the variant data into the safe array
    sa = StoreSafeArray(values, VT_VARIANT);

    // store the safe array in a variant
    VARIANT variant;
    variant.parray = sa;
    variant.vt = VT_ARRAY | VT_VARIANT;

    return _variant_t(variant);
}

void get_data(USHORT count, ItemType types[], VARIANT values[]) 
{
    for (size_t i = 0; i < count; i++)
    {
        if (types[i] == ItemType::ARRAY)
        {
            std::vector<_variant_t> nominalData = get_values();
            values[i] = populateVariantSafeArray(values);
        }
        else
        { 
            // get_value returns a primitive type and this works
            auto data = get_value();
            values[i] = _variant_t(data);
        }
    }
}
0

There are 0 best solutions below