问题描述:
该问题非常隐蔽,很难查,场景:
在AssocDeepClone反应器中,维护了一个ZcDbAssocDeepCloneData的Data数组,每次克隆开始beginDeepClone时,都会往该数组插入一个Data,Data中记录了传入IdMap的地址,以及克隆过程中收集的数据。在clone过程中会往全局静态BTRPair数组记录源块定义和目标块定义的对,用于xlate时克隆相应块中的关联网络。
在endDeepClone时,会根据传入IdMap,从数组中移除相应的Data。
在abortDeepClone时,会直接清空该Data数组。
正常情况下,克隆开始插入一个Data,结束时删除,这样不会有问题。
和wblock/insert接口不同,wblockCloneObjects和deepCloneObjects支持deferXlation,默认情况下deferXlation为false,此时调用该接口能正常删除Data。
1.当用户想要为objects设置不同的owner时,可以将objects分组,多次调用cloneObjects接口,并且在调用时将deferXlation设置为true,仅在最后一次调用时设为false,去做xlate。如果客户调用该接口时,忘记在最后一次将deferXlation设为false,此时就有问题了。
我们不知道该克隆是否结束,所以没法确定是否要清理Data数组,此时Data中记录的IdMap地址很可能已经变为野指针了。
2.多次调用时传入的AcDbIdMapping应该是同一个对象,如果写在一个循环里,每次调用这个接口之后AcDbIdMapping析构了导致崩溃,应该把这个对象提到循环外,这样符合文档上的用法(不这么做克隆的xlate应该会有一些正确性问题)。
总结:
克隆来自不同所有者的对象
如果要克隆来自不同所有者的一组对象,则需要将对象 ID 集划分为每个所有者的单独组。(克隆的对象及其所有者应属于同一数据库。在本节的示例中,将要克隆的模型空间对象添加到 中,将要克隆的图纸空间对象添加到:objListMS,objListPS:
objListMS.append(objId);
objListPS.append(objId);
然后,使用相同的 ID 映射调用该函数两次。必须使用单个 ID 映射进行所有克隆,才能正确完成参考翻译。在第一次调用时,该参数设置为 。在第二次(最后一次)调用时,默认为 :deepCloneObjects() deferXlation kTrue deepCloneObjects() deferXlation kFalse。
acdbHostApplicationServices()->workingDatabase()->
deepCloneObjects(mslist, modelSpaceId, idMap, Adesk::kTrue);
acdbHostApplicationServices()->workingDatabase()->
deepCloneObjects(pslist, paperSpaceId, idMap);
以下代码深度克隆属于不同所有者的对象示例:
void
cloneDiffOwnerObjects()
{
// Step 1: Obtain the set of objects to be cloned.
// For the two owners we'll use model space and
// paper space, so we must perform two acedSSGet() calls.
// calls.
//
acutPrintf("\nSelect entities to be cloned to"
" Model Space");
ads_name ssetMS;
acedSSGet(NULL, NULL, NULL, NULL, ssetMS);
long lengthMS;
acedSSLength(ssetMS, &lengthMS);
acutPrintf("\nSelect entities to be cloned to"
" Paper Space");
ads_name ssetPS;
if (acedSSGet(NULL, NULL, NULL, NULL, ssetPS)
!= RTNORM && lengthMS == 0)
{
acutPrintf("\nNothing selected");
return;
}
long lengthPS;
acedSSLength(ssetPS, &lengthPS);
// Step 2: Add obtained object IDs to the lists of
// objects to be cloned: one list for objects to
// be owned by model space and one for those to
// be owned by paper space.
AcDbObjectId ownerId = AcDbObjectId::kNull;
// For model space
//
AcDbObjectIdArray objListMS;
for (int i = 0; i < lengthMS; i++) {
ads_name ent;
acedSSName(ssetMS, i, ent);
AcDbObjectId objId;
acdbGetObjectId(objId, ent);
// Check to be sure this has the same owner as the first
// object.
//
AcDbObject *pObj;
acdbOpenObject(pObj, objId, AcDb::kForRead);
if (pObj->ownerId() == ownerId)
objListMS.append(objId);
else if (i == 0) {
ownerId = pObj->ownerId();
objListMS.append(objId);
}
pObj->close();
}
acedSSFree(ssetMS);
// For paper space
//
ownerId = AcDbObjectId::kNull;
AcDbObjectIdArray objListPS;
for (i = 0; i < lengthPS; i++) {
ads_name ent;
acedSSName(ssetPS, i, ent);
AcDbObjectId objId;
acdbGetObjectId(objId, ent);
// Check to be sure this has the same owner as the first
// object.
//
AcDbObject *pObj;
acdbOpenObject(pObj, objId, AcDb::kForRead);
if (pObj->ownerId() == ownerId)
objListPS.append(objId);
else if (i == 0) {
ownerId = pObj->ownerId();
objListPS.append(objId);
}
pObj->close();
}
acedSSFree(ssetPS);
// Step 3: Get the object ID of the desired owners for
// the cloned objects. We're using model space and
// paper space for this example.
//
AcDbBlockTable *pBlockTable;
acdbHostApplicationServices()->workingDatabase()
->getSymbolTable(pBlockTable, AcDb::kForRead);
AcDbObjectId modelSpaceId, paperSpaceId;
pBlockTable->getAt(ACDB_MODEL_SPACE, modelSpaceId);
pBlockTable->getAt(ACDB_PAPER_SPACE, paperSpaceId);
pBlockTable->close();
// Step 4: Create a new ID map.
//
AcDbIdMapping idMap;
// Step 5: Call deepCloneObjects().
//
acdbHostApplicationServices()->workingDatabase()
->deepCloneObjects(objListMS, modelSpaceId, idMap,
Adesk::kTrue);
acdbHostApplicationServices()->workingDatabase()
->deepCloneObjects(objListPS, paperSpaceId, idMap);
// Now we can go through the ID map and do whatever we'd
// like to the original and/or clone objects.
//
// For this example we'll print out the object IDs of
// the new objects resulting from the cloning process.
//
AcDbIdMappingIter iter(idMap);
for (iter.start(); !iter.done(); iter.next()) {
AcDbIdPair idPair;
iter.getMap(idPair);
if (!idPair.isCloned())
continue;
acutPrintf("\nObjectId is: %Ld",
idPair.value().asOldId());
}
}
| 英文空间链接 |
|---|
★中望CAD中ZRX开发wblockCloneObjects使用不当造成崩溃如何处理?:https://confluence.zwcad.com/pages/viewpage.action?pageId=298355923