(continued with Display Custom Properties of DWG in Navisworks – 1)
7. To Create a COM Wrapper for the custom entity, you can either place the COM implementation in an ARX project or in the same ObjectDBX project where your custom entity exists. Here we are going to see how to place the COM wrapper along with the custom entity itself. If you are interested to create a separate ARX, you can follow the same step explained to create a custom entity where instead of selecting a Project type as “ObjecDBX” , select the Application Type as “ObjectARX” (as mentioned in Step1 – Application Type Dialog) and the continue with the following steps.
8. Input the wrapper name as “NW_DBX_Curve_Wrapper”. In the COM wrapper tab, put the name of your DBX without the .dbx extension as "AdskDemoCurve" in the “DBX Classname” textbox . Select Ok to finish, and build to test for errors. Take a look NW_DBX_Curve_Wrapper.cpp and .h to see what the wizard has added for us.
9. Add necessary code for the custom entity
9.1 AsdkDemoCurve.h
public:
// assign the CLSID of the wrapper to
//be returned by the subGetClassID
// method of our custom entity
virtual Acad::ErrorStatus subGetClassID(CLSID * pClsid) const;
//set the member variable - long
Acad::ErrorStatus setPropertyLong(long val) ;
//get the member variable - long
long getPropertyLong()const;
//set the member variable - double
Acad::ErrorStatus setPropertyDouble(double val) ;
//get the member variable - double
long getPropertyDouble()const;
private:
// member variable - long
long m_propertylong;
//member variable - double
double m_propertydouble;
9.2 AsdkDemoCurve.cpp
// include the COM wrapper
#include "NW_AutoCAD_OE_Sample_i.c"
//initialize the member variables
AsdkDemoCurve::AsdkDemoCurve () : AcDbCurve ()
{
m_propertylong = 2;
m_propertydouble = 10;
}
//draw some custom geometires.
//To similfy the sample, the code draws a
//fixed circle and text.
Adesk::Boolean AsdkDemoCurve::
subWorldDraw (AcGiWorldDraw *mode)
{
assertReadEnabled () ;
mode->geometry().circle(
AcGePoint3d(m_propertydouble,0,0),
10,
AcGeVector3d(0,0,1));
mode->geometry().text(
AcGePoint3d(m_propertydouble,0,0),
AcGeVector3d(0,0,1),
AcGeVector3d(1,0,0),
m_propertylong,1,
0,
_T("MyCurve"));
return (AcDbCurve::subWorldDraw (mode)) ;
}
// return the COM wrapper ID
Acad::ErrorStatus AsdkDemoCurve::subGetClassID(CLSID * pClsid) const
{
//locate the file ' NW_AutoCAD_OE_Sample_i.c ',
// and open it in VS (this //file may not already be
// included in the VC project).
// Look for and copy
//the CLSID definition name (eg CLSID_NW_DBX_Curve_Wraper)
assertReadEnabled();
*pClsid=CLSID_NW_DBX_Curve_Wraper;
return Acad::eOk;
}
//set the member variable - long
Acad::ErrorStatus AsdkDemoCurve::setPropertyLong(long val)
{
assertWriteEnabled();
m_propertylong = val;
return Acad::eOk ;
}
//get the member variable - long
long AsdkDemoCurve::getPropertyLong()const
{
assertReadEnabled();
return m_propertylong;
}
//set the member variable - double
Acad::ErrorStatus AsdkDemoCurve::setPropertyDouble (double val)
{
assertWriteEnabled();
m_propertydouble = val;
return Acad::eOk ;
}
//get the member variable - double
long AsdkDemoCurve::getPropertyDouble()const
{
assertReadEnabled();
return m_propertydouble;
}
10. Now we provide the interface methods to communicate with those two custom properties of this entity, a long and a double. Switch to Class View, select INW_DBX_Curve_Wrapper and Add Property. Select the property type Long and provide the name “PropertyLong”. Then finish. Repeat the operation to provide a double property.
10.1 NW_DBX_Curve_Wraper.h
//configure in which category
//(of AutoCAD) the properties would be displayed.
// In this sample, we put them in Data category.
//IOPMPropertyExtension
BEGIN_OPMPROP_MAP()
//----- Use the OPMPROP_ENTRY/OPMPROP_CAT_ENTRY macros for each of your properties
OPMPROP_ENTRY(0, 0x00000001,
PROPCAT_Data, 0, 0, 0,
_T(""), 0, 1,
IID_NULL,
IID_NULL, "")
OPMPROP_ENTRY(0, 0x00000002,
PROPCAT_Data, 0, 0, 0,
_T(""), 0, 1,
IID_NULL,
IID_NULL, "")
END_OPMPROP_MAP()
//IOPMPropertyExtensionImpl
// It is a pity VS does not generate the properties
//Set/Get methods codes
//automatically. We need to write as below:
public:
//INW_DBX_Curve_Wraper
STDMETHOD(get_PropertyLong)(/*[out, retval]*/ LONG *pVal);
STDMETHOD(put_PropertyLong)(/*[in]*/ LONG newVal);
STDMETHOD(get_PropertyDouble)(/*[out, retval]*/ DOUBLE *pVal);
STDMETHOD(put_PropertyDouble)(/*[in]*/ DOUBLE newVal);
10.2 NW_DBX_Curve_Wraper.cpp
//get property - long
STDMETHODIMP CNW_DBX_Curve_Wraper::
get_PropertyLong(LONG *pVal)
{
try
{
Acad::ErrorStatus es;
AcAxObjectRefPtr<AsdkDemoCurve>
pLine(&m_objRef,AcDb::kForRead,
Adesk::kTrue);
if((es=pLine.openStatus()) != Acad::eOk)
throw es;
*pVal = pLine->getPropertyLong();
}
catch(const Acad::ErrorStatus)
{
return Error(L"Failed to open object.",
IID_INW_DBX_Curve_Wraper,E_FAIL);
}
catch(const HRESULT hr)
{
return Error(L"Invalid argument.",
IID_INW_DBX_Curve_Wraper,hr);
}
return S_OK;
}
//set property - long
STDMETHODIMP CNW_DBX_Curve_Wraper::
put_PropertyLong(LONG newVal)
{
try
{
Acad::ErrorStatus es;
AcAxObjectRefPtr<AsdkDemoCurve>
pLine(&m_objRef,AcDb::kForWrite,Adesk::kTrue);
if((es=pLine.openStatus()) != Acad::eOk)
throw es;
pLine->setPropertyLong(newVal);
}
catch(const Acad::ErrorStatus)
{
return Error(L"Failed to set PropertyLong.",
IID_INW_DBX_Curve_Wraper,E_FAIL);
}
catch(const HRESULT hr)
{
return Error(L"Invalid argument.",
IID_INW_DBX_Curve_Wraper,hr);
}
return S_OK;
}
//get property - double
STDMETHODIMP CNW_DBX_Curve_Wraper::
get_PropertyDouble(DOUBLE *pVal)
{
try
{
Acad::ErrorStatus es;
AcAxObjectRefPtr<AsdkDemoCurve>
pLine(&m_objRef,AcDb::kForRead,
Adesk::kTrue);
if((es=pLine.openStatus()) != Acad::eOk)
throw es;
*pVal = pLine->getPropertyDouble();
}
catch(const Acad::ErrorStatus)
{
return Error(L"Failed to open object.",
IID_INW_DBX_Curve_Wraper,E_FAIL);
}
catch(const HRESULT hr)
{
return Error(L"Invalid argument.",
IID_INW_DBX_Curve_Wraper,hr);
}
return S_OK;
}
//set property - double
STDMETHODIMP CNW_DBX_Curve_Wraper::
put_PropertyDouble(DOUBLE newVal)
{
try
{
Acad::ErrorStatus es;
AcAxObjectRefPtr<AsdkDemoCurve> pLine(
&m_objRef,AcDb::kForWrite,
Adesk::kTrue);
if((es=pLine.openStatus()) != Acad::eOk)
throw es;
pLine->setPropertyDouble(newVal);
}
catch(const Acad::ErrorStatus)
{
return Error(L"Failed to set PropertyLong.",
IID_INW_DBX_Curve_Wraper,E_FAIL);
}
catch(const HRESULT hr)
{
return Error(L"Invalid argument.",
IID_INW_DBX_Curve_Wraper,hr);
}
return S_OK;
}
11. Now build the DBX to see if there is error.
12. Run AutoCAD, and load our DBX. This will register the COM server automatically.
13. Optional: We should now verify that the ObjectDBX registry entries have been made properly. Run RegEdit.exe to access the Windows registry, and navigate to HKEY_LOCAL_MACHINE>SOFTWARE>Autodesk>ObjectDBX>R18.1>ActiveXCLSID. Look for a key called AsdkDemoCurve. The CLSID string value within it should be the same as the CLSID found in the IDL file for your custom wrapper, under INW_DBX_Curve_Wraper. Example:
We can now create a simple COM client to create and manipulate our custom line.. This will allow us to use objects defined by this TLB, namely, our custom wrapper. Create a VB.NET project, add the tlb and add the following code:
<CommandMethod("addEnt")> _
Public Sub addEnt()
Dim oAcadApp As AcadApplication = Autodesk.AutoCAD.ApplicationServices.Application.AcadApplication
Dim myDemo As NW_DBX_Curve_Wraper
myDemo = oAcadApp.ModelSpace.AddCustomObject("AsdkDemoCurve")
End Sub
Load the .NET dll and run command addEnt.