【发布时间】:2019-06-28 00:33:13
【问题描述】:
我正在尝试创建和读取 SAFEARRAY(MyUDT)*,其中 MyUDT 包含 SAFEARRAY,但是当我尝试读取它时出现“访问冲突”异常。
我定义了以下结构和枚举:
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, ¤t_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, ¤t_position, ¤t_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 **)¤t_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。
感谢您的帮助。
已解决
我找到了解决方案,我为所有可能遇到相同问题的用户报告了代码。基本上,诀窍是创建一个 VARIANT 的 SAFEARRAY,并用 CollisionDetectorMultiPosition 填充 VARIANT 结构。
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, ¤t_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 **)¤t_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);
}
【问题讨论】:
-
尝试通过正确格式化来澄清您的问题
-
我想知道
recordset_info是否应该为空。 -
@john 我试着把初始化去掉nullptr,结果还是一样
-
@Davide 不,你误会了。我认为 recordset_info 应该 not 为空。但我真的不知道我在说什么。
-
最重要的是 - 你有时打电话给
SafeArrayUnaccessData而不先打电话给SafeArrayAccessData