Protocol Extension Example

This protocol extension example is divided into three parts:

// This is the AsdkEntTemperature protocol extension abstract base
// class. Notice that this is the lowest level that uses
// the ACRX macros.
// 
class AsdkEntTemperature : public AcRxObject
{
public:
    ACRX_DECLARE_MEMBERS(AsdkEntTemperature);
    virtual double reflectedEnergy(AcDbEntity*) const = 0;
};
ACRX_NO_CONS_DEFINE_MEMBERS(AsdkEntTemperature, AcRxObject);
// This is the default implementation to be attached to AcDbEntity
// as a catch-all. This guarantees that this protocol extension will
// be found for any entity, so the search up the AcRxClass tree will
// not fail and abort AutoCAD.
//
class AsdkDefaultTemperature : public AsdkEntTemperature
{
public:
    virtual double reflectedEnergy(AcDbEntity* pEnt) const;
};
double
AsdkDefaultTemperature::reflectedEnergy(
    AcDbEntity* pEnt) const
{
    acutPrintf(
        "\nThis entity has no area, and no reflection.\n");
    return -1.0;
}
// AsdkEntTemperature implementation for Regions
//
class AsdkRegionTemperature : public AsdkEntTemperature
{
public:
    virtual double reflectedEnergy(AcDbEntity* pEnt) const;
};
double
AsdkRegionTemperature::reflectedEnergy(
    AcDbEntity* pEnt) const
{
    AcDbRegion *pRegion = AcDbRegion::cast(pEnt);
    if (pRegion == NULL)
        acutPrintf("\nThe impossible has happened!");
    // Compute the reflected energy as the region area multiplied
    // by a dummy constant.
    //
    double retVal;
    if (pRegion->getArea(retVal) != Acad::eOk)
        return -1.0;
    return retVal * 42.0;
}
// AsdkEntTemperature implementation for circles
//
class AsdkCircleTemperature : public AsdkEntTemperature
{
public:
    virtual double reflectedEnergy(AcDbEntity* pEnt) const;
};
double
AsdkCircleTemperature::reflectedEnergy(
    AcDbEntity* pEnt) const
{
    AcDbCircle *pCircle = AcDbCircle::cast(pEnt);
    // Compute the reflected energy in a manner distinctly
    // different than for AcDbRegion.
    // 
    return pCircle->radius() * 6.21 * 42.0;
}
// This function has the user select an entity and then
// calls the reflectedEnergy() function in the protocol
// extension class attached to that entity's class.
// 
void
energy()
{
    AcDbEntity *pEnt;
    AcDbObjectId pEntId;
    ads_name en;
    ads_point pt;
    if (acedEntSel("\nSelect an Entity:  ", en, pt)
        != RTNORM)
    {
        acutPrintf("Nothing Selected\n");
        return;
    }
    acdbGetObjectId(pEntId, en);
    acdbOpenObject(pEnt, pEntId, AcDb::kForRead);
    // call the protocol extension class's method
    //
    double eTemp = ACRX_X_CALL(pEnt,
        AsdkEntTemperature)->reflectedEnergy(pEnt);
    acutPrintf("\nEnergy == %f\n", eTemp);
    pEnt->close();
}
// Pointers for protocol extension objects. These pointers
// are global so that they can be accessed during
// initialization and cleanup.
// 
AsdkDefaultTemperature *pDefaultTemp;
AsdkRegionTemperature *pRegionTemp;
AsdkCircleTemperature *pCircleTemp;
// Initialization function called from acrxEntryPoint() during
// kInitAppMsg case. This function is used to add commands
// to the command stack and to add protocol extension
// objects to classes.
// 
void
initApp()
{
    acrxRegisterService("AsdkTemperature");
    AsdkEntTemperature::rxInit();
    acrxBuildClassHierarchy();
    pDefaultTemp = new AsdkDefaultTemperature();
    pRegionTemp = new AsdkRegionTemperature();
    pCircleTemp = new AsdkCircleTemperature();
    // Add the protocol extension objects to the appropriate
    // AcRxClass objects.
    //
    AcDbEntity::desc()->addX(AsdkEntTemperature::desc(),
        pDefaultTemp);
    AcDbRegion::desc()->addX(AsdkEntTemperature::desc(),
        pRegionTemp);
    AcDbCircle::desc()->addX(AsdkEntTemperature::desc(),
        pCircleTemp);
    acedRegCmds->addCommand("ASDK_TEMPERATURE_APP",
        "ASDK_ENERGY", "ENERGY", ACRX_CMD_TRANSPARENT,
        energy);
}
void
unloadApp()
{
    delete acrxServiceDictionary->remove("AsdkTemperature");
    acedRegCmds->removeGroup("ASDK_TEMPERATURE_APP");
    // Remove protocol extension objects from the AcRxClass
    // object tree.  This must be done before removing the
    // AsdkEntTemperature class from the ACRX runtime class
    // hierarchy, so the AsdkEntTemperature::desc()
    // still exists.
    // 
    AcDbEntity::desc()->delX(AsdkEntTemperature::desc());
    delete pDefaultTemp;
    AcDbRegion::desc()->delX(AsdkEntTemperature::desc());
    delete pRegionTemp;
    AcDbCircle::desc()->delX(AsdkEntTemperature::desc());
    delete pCircleTemp;
    // Remove the AsdkEntTemperature class from the ARX
    // runtime class hierarchy.
    //
    deleteAcRxClass(AsdkEntTemperature::desc());
}
extern "C" AcRx::AppRetCode
acrxEntryPoint(AcRx::AppMsgCode msg, void* appId)
{
    switch (msg) {
    case AcRx::kInitAppMsg:
        acrxDynamicLinker->unlockApplication(appId);
        acrxDynamicLinker->registerAppMDIAware(appId);
        initApp();
        break;
    case AcRx::kUnloadAppMsg:
        unloadApp();
    }
    return AcRx::kRetOK;
}