Exposing Custom Entity & XDATA Properties in the GstarCAD Ctrl+1 Palette via OPM COM Interfaces (dev-cookbook-20)
Implement IDynamicProperty2 and ICategorizeProperties in C++ GRX to display custom categorized dropdowns and live engineering properties in GstarCAD 2027's Properties Palette.
1. How the Object Property Manager (`OPM`) Populates the `Ctrl+1` Palette
When an engineer selects an entity in GstarCAD 2027 and opens the Properties Palette (`Ctrl+1`), the Object Property Manager (`OPM`) inspects both the entity's static COM Automation wrapper (`IAcadEntity`) and any runtime **Dynamic Properties (`IDynamicProperty2`)** registered with the `IPropertyManager2` collection for that `AcRxClass`. Unlike static COM wrappers—which require compiling and registering a full `.tlb` IDL type library—`IDynamicProperty2` allows a C++ GRX plugin to inject custom categorized rows, unit-formatted numeric fields, and enumerated dropdown lists onto *any* native entity (such as `AcDbBlockReference` or `AcDbPolyline`) without subclassing `AcDbEntity`.
2. C++ ATL COM Implementation of `IDynamicProperty2` & `IDynamicEnumProperty`
The following C++ ATL class exposes a custom **"Fire Resistance Rating"** enumerated dropdown (`REI 60`, `REI 120`, `REI 180`, `REI 240`) under an **"ISO Structural BIM"** category in the Properties Palette whenever a user selects a wall or structural column in GstarCAD 2027, reading and writing the value directly to the entity's Extension Dictionary:
#include "grxHeaders.h"
#include "dynprops.h"
class ATL_NO_VTABLE GcFireRatingDynProp :
public CComObjectRootEx<CComSingleThreadModel>,
public IDynamicProperty2,
public IDynamicEnumProperty,
public ICategorizeProperties
{
public:
BEGIN_COM_MAP(GcFireRatingDynProp)
COM_INTERFACE_ENTRY(IDynamicProperty2)
COM_INTERFACE_ENTRY(IDynamicEnumProperty)
COM_INTERFACE_ENTRY(ICategorizeProperties)
END_COM_MAP()
STDMETHOD(GetDisplayName)(BSTR* pBstrName) override {
*pBstrName = ::SysAllocString(L"Fire Resistance Class");
return S_OK;
}
STDMETHOD(IsPropertyEnabled)(IUnknown* pUnk, BOOL* pbEnabled) override {
*pbEnabled = TRUE;
return S_OK;
}
// Group under custom collapsible category in Ctrl+1 Properties Palette
STDMETHOD(MapPropertyToCategory)(DISPID dispid, PROPCAT* ppropcat) override {
*ppropcat = 101;
return S_OK;
}
STDMETHOD(GetCategoryName)(PROPCAT propcat, LCID lcid, BSTR* pbstrName) override {
*pbstrName = ::SysAllocString(L"ISO 19650 Structural BIM");
return S_OK;
}
// Enumerated Dropdown Options (0 = REI 60, 1 = REI 120, 2 = REI 180, 3 = REI 240)
STDMETHOD(GetNumPropertyValues)(LONG* numValues) override {
*numValues = 4;
return S_OK;
}
STDMETHOD(GetPropValueName)(LONG index, BSTR* valueName) override {
static const wchar_t* kRatings[] = { L"REI 60", L"REI 120", L"REI 180", L"REI 240" };
if (index >= 0 && index < 4) *valueName = ::SysAllocString(kRatings[index]);
return S_OK;
}
};
3. Binding `IDynamicProperty2` to Native `AcRxClass` Descriptors
To attach `GcFireRatingDynProp` to all `AcDbPolyline` or `AcDbBlockReference` objects upon plugin initialization (`On_kInitAppMsg`), retrieve the class property manager via the macro GET_OPMPROPERTY_MANAGER(AcDbBlockReference::desc()) and call `AddProperty()`. When your plugin unloads (`On_kUnloadAppMsg`), always invoke `RemoveProperty()` and release the COM interface pointer so the Properties Palette refreshes cleanly without stale COM references.
- Document Locking Inside `SetCurrentValueData()`: Because the Properties Palette is a modeless UI window running in the main application context, always instantiate
AcAxDocLock docLock(objId.database(), AcAxDocLock::kNormal);inside `SetCurrentValueData()` before opening the target `AcDbObjectId` for write. - Real-Time Viewport Graphics Refresh: Call `m_pNotifySink->OnChanged(this)` after updating the Xrecord or XDATA so the Properties Palette and any associated viewport Overrules redraw immediately.
4. Implementing Per-Pickset Batch Editing & Unit Formatting in OPM
When a drafter selects 50 structural columns at once and changes your custom **"Fire Resistance Class"** dropdown in the `Ctrl+1` Properties Palette from `REI 60` to `REI 120`, GstarCAD's OPM host automatically loops through all 50 selected `LONG_PTR objectID` handles and invokes `IDynamicProperty2::SetCurrentValueData(LONG_PTR objectID, const VARIANT varData)` once per entity.
If two selected columns currently hold different fire ratings (`REI 60` vs. `REI 180`), OPM compares the `VARIANT` values returned by `GetCurrentValueData()` across the pickset and automatically displays the blank **`*VARIES*`** state in the combo box—matching native GstarCAD property behavior with zero extra UI code.
Validate This Workflow in GstarCAD 2027
Engineered by Suzhou Gstarsoft Co., Ltd. (SSE: 688657), GstarCAD 2027 delivers 100% native AC1032 DWG binary fidelity, perpetual licensing sovereignty, and zero-day AutoCAD command parity.