Категоризировать свойства
Вы не можете хотеть, чтобы все ваши свойства обнаружились под “Общей” категорией, так что эта следующая секция демонстрирует, как использовать встроенные категории.
1 Идут к Представлению Класса в IDE Visual C++, щелкают правой кнопкой мыши на заказном интерфейсе примитива (типа IAsdkSquareWrapper), и выбирают AddProperty. Добавьте свойства для квадратного центра и номера ID.
2 Затем изменяют образование из объекта COM, чтобы включить IOPMPropertyExtensionImpl и IOPMPropertyExpander:
public IOPMPropertyExtensionImpl<CAsdkSquareWrapper>,
public IOPMPropertyExpander
3 Добавляют интерфейсы к карте интерфейса COM:
COM_INTERFACE_ENTRY(IOPMPropertyExtension)
COM_INTERFACE_ENTRY(ICategorizeProperties)
COM_INTERFACE_ENTRY(IPerPropertyBrowsing)
COM_INTERFACE_ENTRY(IOPMPropertyExpander)
4 Добавляют объявление для интерфейса IOPMPropertyExtension:
// IOPMPropertyExtension
//
BEGIN_OPMPROP_MAP()
OPMPROP_ENTRY(0, 0x00000001, PROPCAT_Data, \
0, 0, 0, "", 0, 1, IID_NULL, IID_NULL, "")
OPMPROP_ENTRY(0, 0x00000003, PROPCAT_Geometry, \
0, 0, 0, "", 0, 1, IID_NULL, IID_NULL, "")
END_OPMPROP_MAP()
5 Добавляют следующий две подставляемых функции к классу:
STDMETHOD(GetCategoryName)(
THIS_
/* [in] */ PROPCAT propcat,
/* [in] */ LCID lcid,
/* [out] */ BSTR* pbstrName)
{return S_FALSE;}
virtual HINSTANCE GetResourceInstance()
{
return _Module.GetResourceInstance();
}
6 Добавляют объявления для следующих функций:
STDMETHOD(GetElementValue)(
/* [in] */ DISPID dispID,
/* [in] */ DWORD dwCookie,
/* [out] */ VARIANT * pVarOut) ;
// Used for property expansion (currently variant types)
//
STDMETHOD(SetElementValue)(
/* [in] */ DISPID dispID,
/* [in] */ DWORD dwCookie,
/* [in] */ VARIANT VarIn) ;
// Used for property expansion (currently variant types)
//
STDMETHOD(GetElementStrings)(
/* [in] */ DISPID dispID,
/* [out] */ OPMLPOLESTR __RPC_FAR *pCaStringsOut,
/* [out] */ OPMDWORD __RPC_FAR *pCaCookiesOut) ;
//Used for property expansion (currently variant types)
//
STDMETHOD(GetElementGrouping)(
/* [in] */ DISPID dispID,
/* [out] */ short *groupingNumber) ;
// Used for property expansion (currently variant types)
//
STDMETHOD(GetGroupCount)(
/* [in] */ DISPID dispID,
/* [out] */ long *nGroupCnt) ;
STDMETHOD(GetPredefinedStrings)(
/* [in] */ DISPID dispID,
/* [out] */ CALPOLESTR *pCaStringsOut,
/* [out] */ CADWORD *pCaCookiesOut);
STDMETHOD(GetPredefinedValue)(
/* [in] */ DISPID dispID,
/* [out] */ DWORD dwCookie,
/* [out] */ VARIANT *pVarOut);
7 Добавляют выполнение для функции в CPP исходном файле. Эти примеры - для объекта AsdkSquare:
STDMETHODIMP CAsdkSquareWrapper::GetElementValue(
/* [in] */ DISPID dispID,
/* [in] */ DWORD dwCookie,
/* [out] */ VARIANT * pVarOut)
{
if (pVarOut == NULL)
return E_POINTER;
AcDbObjectPointer<AsdkSquare> pSq(m_objId, AcDb::kForRead);
if (pSq.openStatus() != Acad::eOk)
return E_ACCESSDENIED;
if (dispID == 0x03) {
AcGePoint3d acgePt;
pSq->squareCenter(acgePt);
AcAxPoint3d acaxPt(acgePt);
::VariantCopy(pVarOut,&CComVariant(acaxPt[dwCookie]));
}
return S_OK;
}
STDMETHODIMP CAsdkSquareWrapper::SetElementValue(
/* [in] */ DISPID dispID,
/* [in] */ DWORD dwCookie,
/* [in] */ VARIANT VarIn)
{
AcDbObjectPointer<AsdkSquare> pSq(m_objId, AcDb::kForRead);
if (pSq.openStatus() != Acad::eOk)
return E_ACCESSDENIED;
if (dispID == 0x03) {
AcGePoint3d acgePt;
pSq->squareCenter(acgePt);
AcAxPoint3d acaxPt(acgePt);
acaxPt[dwCookie] = V_R8(&VarIn);
pSq->upgradeOpen();
pSq->setSquareCenter(acaxPt);
}
return S_OK;
}
STDMETHODIMP CAsdkSquareWrapper::GetElementStrings(
/* [in] */ DISPID dispID,
/* [out] */ OPMLPOLESTR __RPC_FAR *pCaStringsOut,
/* [out] */ OPMDWORD __RPC_FAR *pCaCookiesOut)
{
if (dispID == 0x03)
{
long size;
size = 3;
pCaStringsOut->pElems =
(LPOLESTR *)::CoTaskMemAlloc(sizeof(LPOLESTR) * size);
pCaCookiesOut->pElems =
(DWORD *)::CoTaskMemAlloc(sizeof(DWORD) * size);
for (long i=0;i<size;i++)
pCaCookiesOut->pElems[i] = i;
pCaStringsOut->cElems = size;
pCaCookiesOut->cElems = size;
pCaStringsOut->pElems[0] = ::SysAllocString(L"Center X");
pCaStringsOut->pElems[1] = ::SysAllocString(L"Center Y");
pCaStringsOut->pElems[2] = ::SysAllocString(L"Center Z");
}
return S_OK;
}
STDMETHODIMP CAsdkSquareWrapper::GetElementGrouping(
/* [in] */ DISPID dispID,
/* [out] */ short *groupingNumber)
{
return E_NOTIMPL;
}
STDMETHODIMP CAsdkSquareWrapper::GetGroupCount(
/* [in] */ DISPID dispID,
/* [out] */ long *nGroupCnt)
{
return E_NOTIMPL;
}
STDMETHODIMP CAsdkSquareWrapper::GetPredefinedStrings(
DISPID dispID, CALPOLESTR *pCaStringsOut,
CADWORD *pCaCookiesOut)
{
return E_NOTIMPL;
}
STDMETHODIMP CAsdkSquareWrapper::GetPredefinedValue(
DISPID dispID, DWORD dwCookie, VARIANT *pVarOut)
{
return E_NOTIMPL;
}
Динамические Свойства и OPM
Проблема с информацией типа состоит в том, что это является статическим. Это определено во времени компиляции в .idl файлах и не может изменяться легко во время выполнения. Microsoft обеспечивает интерфейсы, наиболее особенно ITypeInfo2 и ICreateTypeInfo, для так называемого динамического создания информации типа. Однако, эти интерфейсы только позволяют Вам добавлять информацию типа от существующей структуры ITypeInfo, которая относится к существующему интерфейсу отправки. Не имеется никакого метода во время выполнения для опроса объекта относительно его информации свойства. Чтобы заполнять этот промежуток и позволять любому DLL добавлять свойства к OPM, IDynamicProperty интерфейс был определен. Это позволяет Вам осуществлять IDynamicProperty полученный класс для каждого свойства, которое Вы желаете добавить к OPM. OPM может тогда вызывать методы этого класса, чтобы получить всю информацию, которую требоваться отобразить любой тип свойства.
IPropertyManager управляет, как OPM может получить указатели на эти интерфейсы свойства во время выполнения. Для каждого объекта AcRxClass в AutoCAD, клиент может получить указатель на объект, который осуществляет IPropertyManager. Это обработано внутренне через расширения протокола. Как только Вы имеете менеджера свойства для AcRxClass, Вы заинтересованы, Вы можете добавлять ваши классы свойства к этому через IPropertyManager:: AddProperty (). Когда пользователь выбирает объект того класса, OPM получит менеджера свойства для того класса, перечислит все классы свойства, и опрашивать те классы для их информации свойства, которую это тогда отобразит наряду с статическими свойствами того объекта. Обратите внимание, что класс IDynamicProperty не делает никакие предположения относительно того, где данные свойства сохранены. Это просто требует, чтобы реализация IDynamicProperty обеспечила это, когда GetCurrentValueData () вызван. Точно так же, когда пользователь изменяет динамическое свойство, OPM назовет SetCurrentValueData () с новым значением, оставляя это до реализации, чтобы решить, как установить то значение. Это оставляет это до Вы, чтобы решить, как делать динамические данные свойства постоянными.
OPM использует IPropertyManager и IDynamicProperty не только для свойств объектов, но также и для отображающихся свойств текущего пространства, когда никакой объект не отобран. Например, когда никакой объект не отобран в рисунке, OPM должен отобразить свойства, касающиеся UCS. Также, некоторые команды требуют, чтобы OPM отобразил информацию свойства (типа команд ОРБИТЫ). Эти ситуации требуют определяющих специальных менеджеров свойства для этих определенных “режимов”. Получение менеджеров свойства для режимов требует слегка различного механизма чем процедура для получения менеджеров свойства для выбираемых объектов. Как упомянуто ранее для свойств объектов, имеется расширение протокола для каждого класса объекта. Этот объект расширения протокола может использоваться разработчиком, чтобы получить менеджера свойства и добавлять его классы свойства. Для модальных ситуаций, будет иметься набор предопределенных расширений протокола на базе данных, что разработчик может использовать, чтобы отыскать менеджера свойства для той модальной ситуации.
IDynamicProperty
Как упомянуто ранее, Вы должны осуществить образец этого класса для каждого свойства, которое Вы желаете добавить к примитивам специфического класса.