Тема: Как добраться до атрибутов (IAcadAttributeReference) блока?

Допустим имеется чертёж в котором есть блок с именем Б.
Нужно прочитать/изменить значение атрибута с именем (Tag) А.
Пишу:
...
IAcadApplication *acad;
CoCreateInstance(...CLSCTX_SERVER, IID_IAcadApplication..., &acad);
...
IAcadDocument *doc;
acad->Documents->Open(filename, OleVariant(TRUE), &doc);
...
IAcadBlock * msp;
doc->get_ModelSpace(&msp);
...
long jcount;        //кол-во Entities
msp->get_Count(&jcount);
IAcadEntity * obj;
for(int j = 0; j < jcount; j++){
  msp->Item(OleVariant(j), &obj);
  long et;
  obj->get_EntityType(&et);
  if(acBlockReference == et){
    IAcadBlockReference *blref;
    obj->QueryInterface(IID_IAcadBlockReference, (void **)&blref);
    BSTR objname;
    blref->get_Name(&objname);
    if(AnsiString(objname) == "Б"){
      VARIANT atts;
      blref->GetAttributes(&atts);
      if(atts.vt & VT_ARRAY){    //на всякий случай
        long klow;
        long kup;
        SafeArrayGetLBound(atts.parray, 1, &klow);
        SafeArrayGetUBound(atts.parray, 1, &kup);
        for(long k = klow; k <= kup; k++){
          IAcadAttributeReference *attr = 0;
          SafeArrayPtrOfIndex(atts.parray, &k, (void **)&attr);
          // SafeArrayAccessData(atts.parray, (void **)&attr); - и так пробовал
          BSTR attv;
          attr->get_TextString(&attv);    //здесь происходит исключение ...Access violation of address...
          ...
      break;
...
Похоже, что attr реально не является IAcadAttributeReference.
Спасибо за ответ.

Re: Как добраться до атрибутов (IAcadAttributeReference) блока?

В документации по ARX есть пример обработки атрибутов. Правда там не com, но думаю, что идея будет ясна.

Re: Как добраться до атрибутов (IAcadAttributeReference) блока?

Господа!
Помогите инвалиду!..
...маленьким примерчиком (начиная с ...GetAttributes).
Пример в OARX SDK чего-то не нашёл (может потому что у меня Core).

Re: Как добраться до атрибутов (IAcadAttributeReference) блока?

To insert a block with attributes into a drawing
Create a block reference entity (AcDbBlockReference).
Call the setBlockTableRecord() function to specify the object ID of the referenced block table record. (The object ID can also be specified directly in the constructor of the block reference.)
Append the block reference to a block table record (model space, paper space, or some other block).
Use a block table record iterator on the referenced block table record, searching for attribute definitions. For each one found, create a new AcDbAttribute entity, fill it in with the attribute definition's data, and then append it to the block reference using the appendAttribute() function.
The following example creates a block reference, fills in the attributes, and appends the reference to the database. It uses global functions to obtain user input. The defineBlockWithAttributes() function shown in the previous section is used to create the block reference. This example uses a block table record iterator to step through the attribute definitions and create a corresponding attribute for each attribute definition. The attribute values are set from the original attribute definition using the setPropertiesFrom() function.

void
addBlockWithAttributes()
{
    // Get an insertion point for the block reference,
    // definition, and attribute definition.
    //
    AcGePoint3d basePoint;
    if (acedGetPoint(NULL, "\nEnter insertion point: ",
        asDblArray(basePoint)) != RTNORM)
        return;
    // Get the rotation angle for the attribute definition.
    //
    double textAngle;
    if (acedGetAngle(asDblArray(basePoint),
        "\nEnter rotation angle: ", &textAngle) != RTNORM)
        return;
    // Define the height used for the attribute definition text.
    //
    double textHeight;
    if (acedGetDist(asDblArray(basePoint),
        "\nEnter text height: ", &textHeight) != RTNORM)
        return;
    // Build the block definition to be inserted.
    //
    AcDbObjectId blockId;
    defineBlockWithAttributes(blockId, basePoint,
        textHeight, textAngle);
    // Step 1: Allocate a block reference object.
    //
    AcDbBlockReference *pBlkRef = new AcDbBlockReference;
    // Step 2: Set up the block reference to the newly
    // created block definition.
    //
    pBlkRef->setBlockTableRecord(blockId);
    // Give it the current UCS normal.
    //
    struct resbuf to, from;
    from.restype = RTSHORT;
    from.resval.rint = 1; // UCS
    to.restype = RTSHORT;
    to.resval.rint = 0; // WCS
    AcGeVector3d normal(0.0, 0.0, 1.0);
    acedTrans(&(normal.x), &from, &to, Adesk::kTrue,
        &(normal.x));
    // Set the insertion point for the block reference.
    //
    pBlkRef->setPosition(basePoint);
    // Indicate the LCS 0.0 angle, not necessarily the UCS 0.0 angle.
    //
    pBlkRef->setRotation(0.0);
    pBlkRef->setNormal(normal);
    // Step 3: Open the current database's model space
    // block Table Record.
    //
    AcDbBlockTable *pBlockTable;
    acdbHostApplicationServices()->workingDatabase()
        ->getSymbolTable(pBlockTable, AcDb::kForRead);
    AcDbBlockTableRecord *pBlockTableRecord;
    pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord,
        AcDb::kForWrite);
    pBlockTable->close();
    // Append the block reference to the model space
    // block Table Record.
    //
    AcDbObjectId newEntId;
    pBlockTableRecord->appendAcDbEntity(newEntId, pBlkRef);
    pBlockTableRecord->close();
    // Step 4: Open the block definition for read.
    //
    AcDbBlockTableRecord *pBlockDef;
    acdbOpenObject(pBlockDef, blockId, AcDb::kForRead);
    // Set up a block table record iterator to iterate
    // over the attribute definitions.
    //
    AcDbBlockTableRecordIterator *pIterator;
    pBlockDef->newIterator(pIterator);
    AcDbEntity *pEnt;
    AcDbAttributeDefinition *pAttdef;
    for (pIterator->start(); !pIterator->done();
        pIterator->step())
    {
        // Get the next entity.
        //
        pIterator->getEntity(pEnt, AcDb::kForRead);
        // Make sure the entity is an attribute definition
        // and not a constant.
        //
        pAttdef = AcDbAttributeDefinition::cast(pEnt);
        if (pAttdef != NULL && !pAttdef->isConstant()) {
            // We have a non-constant attribute definition,
            // so build an attribute entity.
            //
            AcDbAttribute *pAtt = new AcDbAttribute();
            pAtt->setPropertiesFrom(pAttdef);
            pAtt->setInvisible(pAttdef->isInvisible());
            // Translate the attribute by block reference.
            // To be really correct, the entire block
            // reference transform should be applied here.
            //
            basePoint = pAttdef->position();
            basePoint += pBlkRef->position().asVector();
            pAtt->setPosition(basePoint);
            pAtt->setHeight(pAttdef->height());
            pAtt->setRotation(pAttdef->rotation());
            pAtt->setTag("Tag");
            pAtt->setFieldLength(25);
            char *pStr = pAttdef->tag();
            pAtt->setTag(pStr);
            free(pStr);
            pAtt->setFieldLength(pAttdef->fieldLength());
            // The database column value should be displayed.
            // INSERT prompts for this.
            //
            pAtt->setTextString("Assigned Attribute Value");
            AcDbObjectId attId;
            pBlkRef->appendAttribute(attId, pAtt);
            pAtt->close();
        }
        pEnt->close(); // use pEnt... pAttdef might be NULL
    }
    delete pIterator;
    pBlockDef->close();
    pBlkRef->close();
}