objectarx&dummies教程(五)——object management
objectarx&dummies教程(五)——object management
class 5 - object management
introduction
on previous class we have talked about object lifecycle. on this class we will go further on how to manage autocad objects. as i have mentioned every object has its own identification called objectid. this is the key for acquiring its pointer and perform read or write operations.
the standard access method is made by an open operation (for write, for read or for notify), some operations and a close method. another approach, much more efficient is through transactions. this mechanism is much more secure and efficient. let's talk about both methods.
using standard open / close method
this is the most used method but, in other hand, is the most unsafe because you may forget to close the object and then cause access violations or even fatal errors that will cause autocad to terminate.
the global standard function to open objects is called acdbopenobject(). this function will open every object derived from acdbobject class and will provide you a c++ pointer to access the object properties and methods. one of this function signatures is the following:
inline acad::errorstatus acdbopenobject(acdbobject *& pobj, acdbobjectid id, acdb:

penmode mode, bool openerased);
pobjoutput pointer to the opened object
idinput the object id of the object to open
modeinput mode to open object
openerasedinput boolean indicating whether it's ok to open an erased object
this function receives an empty pointer to acdbobject by reference that will be filled out by autocad if there is an object with the provided input variable id. further you need to provide your action intention on the object which can be write, read or notify. the latest parameter indicate if you would like to open the object if it is on erased status. remember we have talked that erased objects remain inside autocad database until the next save operation.
the opening intention is very important because it will limit or not what you can do with the object. if you open an object for read you will not be able to call methods that modify the object's state. in other hand, if you open the object for write you will be able to both modify and read object data. ah, so is better to always open the object for write?
definitely not!
when you open an object for write autocad fires several pre and post procedures on it that causes some performance overhead. if your routine opens several objects and you use the write flag you will certainly loose performance.
the same object can be open for read up to 256 times without close but it is not recommended. you should always close the object as soon as possible. if an object is opened for write you can't open it a second time for write. basically, you need to follow the following rules:
opening objects in different modes
object opened for:kforreadkforwritekfornotify
openedforreadeatmaxreadersewasopenforread(succeeds)
openedforwriteewasopenforwriteewasopenforwrite(succeeds)
openedfornotifyewasopenfornotifyewasopenfornotifyewasopenfornotify
wasnotifying(succeeds)ewasnotifyingewasnotifying
undoewasopenforundoewasopenforundo(succeeds)
the best performance approach is to always open the object for read, analyze if you will modify it and only after this analysis, upgrade its open operation to write using the upgradeopen() method. it will switch the object's state from read to write. to get back to read use the downgradeopen() method. these methods are very useful. a simple operation to use these methods would be:
void changecolor(acdbobjectid id) {
acdbentity* pent = null;
if (acdbopenobject(pent, id, acdb::kforread) == acad::eok) {
if (pent->colorindex() != 3) {
pent->upgradeopen();
pent->setcolorindex(3);
}
else {
acutprintf("\nentity already has color=3");
}
pent->close();
}
}
using transaction method
transactions are a better and much more efficient method to manage objects. they can be nested and this allows you to perform long operations without the limitation of read and write states. basically you need to open a transaction, perform your desired modifications, and at the end, perform an end or abort transaction operation.
transactions are pretty good to use when your application uses dialog boxes that change objects. at your dialog opening you start a new transaction and, depending on user click on ok or cancel button, you call end or abort transaction methods.
when you abort a transaction the whole contained modification are cancelled. in fact, modifications are really applied only when you end a transaction. another great feature is that you can open an object for write several times as you can open for read at the same time.
you don't need to close objects opened through a transaction. the end or abort method will close every object opened and will perform modifications as necessary. it is not recommended to mix standard open / close approach with transactions due some design limitations. you could read more details about this inside sdk documentation. now, let's the see the same operation we did above using transactions:
void changecolor(acdbobjectid id) {
acdbentity* pent = null;
acdbtransactionmanager->starttransaction();
if (acdbtransactionmanager->getobject
((acdbobject*&)pent, id, acdb::kforread) == acad::eok) {
if (pent->colorindex() != 3) {
pent->upgradeopen();
pent->setcolorindex(3);
}
else {
acutprintf("\nentity already has color=3");
}
}
acdbtransactionmanager->endtransaction();
}
this time you open the object using the getobject() method which is much like acdbopenobject() but you don't need to close the object. the whole process is ended at endtransaction() method call. at that time all operations are applied in one operation.