You could approach this in one of two ways, either through Vanilla AutoLISP or through Visual LISP, I'll show you both.
Firstly, we need to get a block to work with, for this we can use entsel.
(setq bEnt (car (entsel "\nSelect Block: ")))
Notice I use 'car' to retrieve the entity name, as entsel will return a two element list upon a successful pick, the first item being the entity name of the object picked and the second item being the point at the center of the aperture that was picked.
We would also need to check that the entity picked is indeed a block, and that it has attributes:
(if
(and
(setq bEnt (car (entsel "\nSelect Block: ")))
(eq "INSERT" (cdr (assoc 0 (entget bEnt))))
(= 1 (cdr (assoc 66 (entget bEnt))))
)
This is how I might start the code, using an IF statement to make sure that the user picks an entity and that the entity picked is indeed an attributed block.
For more reference on the DXF codes used, see here.
Ok, so now that we have our block we can iterate through its attributes, the attributes can be found by using entnext on the INSERT entity name.
We can iterate through all the attributes in this way, by using entnext on the previous attribute entity encountered. When we reach a 'SEQEND' entity, we have iterated through all the attributes that the block contains (we can then get back to the parent block entity using DXF -2 on the SEQEND entity).
In code, we can concisely write this as:
(while
(not
(eq "SEQEND"
(cdr
(assoc 0
(entget
(setq bEnt
(entnext bEnt)
)
)
)
)
)
)
...
)
In this way, the WHILE loop will continue until the SEQEND entity is reached. Notice that we also set the variable 'bEnt' to itself each time so that we are using entnext on the previous subentity retrieved.
In the loop we can now operate on our attributes, for example retrieving the value of attribute with tag 'TAG':
(while
(not
(eq "SEQEND"
(cdr
(assoc 0
(entget
(setq bEnt
(entnext bEnt)
)
)
)
)
)
)
(if (eq "TAG" (cdr (assoc 2 (entget bEnt))))
(setq AttVal (cdr (assoc 1 (entget bEnt))))
)
)
Or perhaps changing its value to something else:
(while
(not
(eq "SEQEND"
(cdr
(assoc 0
(entget
(setq bEnt
(entnext bEnt)
)
)
)
)
)
)
(if (eq "TAG" (cdr (assoc 2 (entget bEnt))))
(entupd
(cdr
(assoc -1
(entmod
(subst
(cons 1 "Lee Mac") (assoc 1 (entget bEnt)) (entget bEnt)
)
)
)
)
)
)
)
Now for the Visual LISP way:
Now that we want to operate on the block through Visual LISP, we need a Visual LISP Object to work with:
(setq bObj (vlax-ename->vla-object bEnt))
We could also test to make sure that the block has attributes using:
(eq :vlax-true (vla-get-HasAttributes bObj))
Now, iterating through the attributes is slightly easier in VL:
(foreach att (vlax-invoke bObj 'GetAttributes)
...
)
Or to include Constant Attributes also:
(foreach att (append (vlax-invoke bObj 'GetAttributes)
(vlax-invoke bObj 'GetConstantAttributes))
...
)
Now that we have bound each attribute object to the symbol 'att' we can operate on these objects within the foreach loop; for example to retrieve the value of an attribute with tag string "TAG":
(foreach att (append (vlax-invoke bObj 'GetAttributes)
(vlax-invoke bObj 'GetConstantAttributes))
(if (eq "TAG" (vla-get-TagString att))
(setq attVal (vla-get-TextString att))
)
)
Notice that we use vlax-invoke in this case, as opposed to vlax-invoke-method or rather just vla-getAttributes. This is because the return of vlax-invoke is a list, which is much easier to deal with using standard Vanilla AutoLISP functions.
If we were to use vlax-invoke-method, or vla-getAttributes we would need to convert the variant that is returned into a list that we can manipulate:
(foreach att
(vlax-safearray->list
(vlax-variant-value
(vla-getAttributes bObj)
)
)
(if (eq "TAG" (vla-get-TagString att))
(setq attVal (vla-get-TextString att))
)
)
This should get you going, if you get stuck, just ask.
Lee