Чтение SAFEARRAY UDT, содержащее SAFEARRAY - PullRequest
0 голосов
/ 04 февраля 2019

Я пытаюсь создать и прочитать SAFEARRAY (MyUDT) *, где MyUDT содержит SAFEARRAY, но когда я пытаюсь прочитать его, я получил исключение "Нарушение прав доступа".

Я определил следующую структуруи enum:

typedef [uuid(...)]
enum CollisionDetectorMoveType
{
CollisionDetectorMoveType_Unknown = -1,
CollisionDetectorMoveType_Move = 0,
CollisionDetectorMoveType_Measure
} CollisionDetectorMoveType;

typedef [uuid(...)]  
struct CollisionDetectorXYZ
{
double X;
double Y;
double Z;
} CollisionDetectorXYZ;

typedef [uuid(...)]
struct CollisionDetectorMultiPosition
{
SAFEARRAY(CollisionDetectorXYZ) pos;
CollisionDetectorMoveType type;
} CollisionDetectorMultiPosition;


bool createTestCollisionDetectorMultiPositionSafeArray(SAFEARRAY** psa)
{

    IRecordInfoPtr recordset_info = nullptr;
    HRESULT hr = GetRecordInfoFromGuids(LIBID_CollisionDetectorLib, 1, 0, 0, UUID_CollisionDetectorMultiPosition, &recordset_info);
    if (FAILED(hr))
    {
        return false;
    }

    SAFEARRAYBOUND safearray_bound;
    memset(&safearray_bound, 0, sizeof(safearray_bound));
    safearray_bound.cElements = 10;
    safearray_bound.lLbound = 0;
    *psa = ::SafeArrayCreateEx(VT_RECORD, 1, &safearray_bound, (PVOID)recordset_info);

    for (size_t i = 0; i < 10; ++i)
    {
        CollisionDetectorMultiPosition multiPosition;
        multiPosition.type = i % 2 == 0 ? CollisionDetectorMoveType_Move : CollisionDetectorMoveType_Measure;
        if (!createTestCollisionDetectorXYZSafeArray(&multiPosition.pos))
        {
            return false;
        }

        LONG current_position = i;
        ::SafeArrayPutElement(*psa, &current_position, &multiPosition);
    }

    ::SafeArrayUnaccessData(*psa);

    return true;
}
}

bool createTestCollisionDetectorXYZSafeArray(SAFEARRAY** psa)
{

    IRecordInfoPtr recordset_info = nullptr;
    HRESULT hr = GetRecordInfoFromGuids(LIBID_CollisionDetectorLib, 1, 0, 0, UUID_CollisionDetectorXYZ, &recordset_info);
    if (FAILED(hr))
    {
        return false;
    }

    SAFEARRAYBOUND safearray_bound;
    memset(&safearray_bound, 0, sizeof(safearray_bound));
    safearray_bound.cElements = 10;
    safearray_bound.lLbound = 0;
    *psa = ::SafeArrayCreateEx(VT_RECORD, 1, &safearray_bound, (PVOID)recordset_info);

    for (size_t i = 0; i < 10; ++i)
    {
        CollisionDetectorXYZ current_point;
        current_point.X = i;
        current_point.Y = i;
        current_point.Z = i;
        LONG current_position = i;
        ::SafeArrayPutElement(*psa, &current_position, &current_point);
    }

    ::SafeArrayUnaccessData(*psa);

    return true;    
}

Затем я пытаюсь создать и прочитать SAFEARRAY:

    SAFEARRAY* psa2 = NULL;
    if (!createTestCollisionDetectorMultiPositionSafeArray(&psa2))
    {
        *retVal = SYSERR;
        return S_OK;
    }

    CollisionDetectorMultiPosition* current_pointer_to_element;
    auto access_result = ::SafeArrayAccessData(psa2, (void **)&current_pointer_to_element);
    if (FAILED(access_result))
    {
        return S_OK;
    }
    LONG upper_bound, lower_bound;
    ::SafeArrayGetLBound(psa2, 1, &lower_bound);
    ::SafeArrayGetUBound(psa2, 1, &upper_bound);

    std::vector<CollisionDetectorMultiPosition> multiPositionVector;
    LONG size = upper_bound - lower_bound + 1;
    for (LONG i = 0; i < size; i++)
    {
        CollisionDetectorMultiPosition this_value;
        ::SafeArrayGetElement(psa2, &i, (void *)&this_value);

        multiPositionVector.push_back(this_value);
    }  

Однако, когда я вызываю :: SafeArrayGetElement (psa2, & i, (void *) & this_value);Я получил исключение.

Что я делаю не так?

Если я просто позвоню

CollisionDetectorMultiPosition multiPosition;
    multiPosition.type = CollisionDetectorMoveType_Move;
    if (!createTestCollisionDetectorXYZSafeArray(&multiPosition.pos))
    {
        *retVal = SYSERR;
        return S_OK;
    }

, я могу читать multiPosition.pos SAFEARRAY без проблем.

Спасибо за вашу помощь.

Решено

Я нашел решение, я сообщаю код для всех пользователей, которые могут иметь ту же проблему.По сути, дело в том, чтобы создать SAFEARRAY из VARIANT и заполнить структуру VARIANT с помощью CollisionDetectorMultiPosition.

CComVariant variant;
variant.vt = VT_RECORD;
variant.pvRecord = &multiPosition;
variant.pRecInfo = recordset_info;

Создание SAFEARRAY

bool createTestCollisionDetectorMultiPositionSafeArray(SAFEARRAY** psa)
{

    IRecordInfoPtr recordset_info;
    HRESULT hr = GetRecordInfoFromGuids(LIBID_CollisionDetectorLib, 1, 0, 0, UUID_CollisionDetectorMultiPosition, &recordset_info);
    if (FAILED(hr))
    {
        return false;
    }

    SAFEARRAYBOUND safearray_bound;
    memset(&safearray_bound, 0, sizeof(safearray_bound));
    safearray_bound.cElements = 10;
    safearray_bound.lLbound = 0;

    *psa = SafeArrayCreate(VT_VARIANT, 1, &safearray_bound);


    for (size_t i = 0; i < 10; ++i)
    {
        CollisionDetectorMultiPosition multiPosition;
        multiPosition.type = i % 2 == 0 ? CollisionDetectorMoveType_Move : CollisionDetectorMoveType_Measure;
        if (!createTestCollisionDetectorXYZSafeArray(&multiPosition.pos))
        {
            return false;
        }

        CComVariant variant;
        variant.vt = VT_RECORD;
        variant.pvRecord = &multiPosition;
        variant.pRecInfo = recordset_info;


        LONG current_position = i;
        ::SafeArrayPutElement(*psa, &current_position, &variant);

        variant.vt = VT_EMPTY;

    }

    ::SafeArrayUnaccessData(*psa);

    return true;
}

Чтение SAFEARRAY

    SAFEARRAY* psa2 = NULL;
    if (!createTestCollisionDetectorMultiPositionSafeArray(&psa2))
    {
        *retVal = AC3SYSERR;
        return S_OK;
    }

    LONG upper_bound, lower_bound;
    ::SafeArrayGetLBound(psa2, 1, &lower_bound);
    ::SafeArrayGetUBound(psa2, 1, &upper_bound);

    std::vector<std::pair<CollisionDetectorMoveType, std::vector<CollisionDetectorXYZ>>> multiPositionVector;
    LONG size = upper_bound - lower_bound + 1;
    for (LONG i = 0; i < size; i++)
    {
        VARIANT this_value;
        VariantInit(&this_value);
        VariantClear(&this_value);

        ::SafeArrayGetElement(psa2, &i, (void *)&this_value);

        CollisionDetectorMultiPosition* this_value2 = (CollisionDetectorMultiPosition *)this_value.pvRecord;

        CollisionDetectorXYZ* current_pointer_to_element;
        auto access_result = ::SafeArrayAccessData(this_value2->pos, (void **)&current_pointer_to_element);
        if (FAILED(access_result))
        {
            return S_OK;
        }

        LONG upper_bound, lower_bound;
        ::SafeArrayGetLBound(this_value2->pos, 1, &lower_bound);
        ::SafeArrayGetUBound(this_value2->pos, 1, &upper_bound);

        std::vector<CollisionDetectorXYZ> moves;
        LONG size = upper_bound - lower_bound + 1;
        for (LONG i = 0; i < size; i++)
        {
            CollisionDetectorXYZ this_value;
            ::SafeArrayGetElement(this_value2->pos, &i, (void *)&this_value);

            moves.push_back(this_value);
        }

        multiPositionVector.push_back(std::make_pair(this_value2->type, moves));

        ::SafeArrayUnaccessData(this_value2->pos);
    }
...