If your COM wrapper class encapsulates a custom object or entity, you need to modify the ATL-generated code to support the appropriate interfaces. The ObjectARX samples\com\AsdkSquareWrapper_dg\square directory contains an example of a wrapper class for a custom entity written as a separate DLL.
You also must make sure the ObjectARX component satisfies the ActiveX Automation requirements, and you must extend your wrapper application to support the ObjectARX components. The following sections provide procedures that show how this is done:
#include "acadi_i.c"
The project you just created contains a considerable amount of generated code. Some of this code must be extended for ObjectARX usage, as demonstrated in the next procedure.
// For a custom object. // public IAcadObjectDispatchImpl<CWrapperClass, &CLSID_WrapperClass,IWrapperClass, &IID_IWrapperClass,&LIBID_LIBRARYLib> // For a custom entity. // public IAcadEntityDispatchImpl<CWrapperClass, &CLSID_WrapperClass,IWrapperClass, &IID_IWrapperClass,&LIBID_LIBRARYLib>
Add the following entries to the COM_MAP:
COM_INTERFACE_ENTRY(IAcadBaseObject) COM_INTERFACE_ENTRY(IAcadObject) COM_INTERFACE_ENTRY(IAcadEntity) // For an entity only. COM_INTERFACE_ENTRY(IRetrieveApplication) COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer) // Only // necessary to support events.
You must implement a special function in your COM code to expose custom objects and entities. The following procedure demonstrates how to provide this support.
Add the following required override to the public declarations of your COM class:
// IAcadBaseObjectImpl // virtual HRESULT CreateNewObject( AcDbObjectId& objId, AcDbObjectID& ownerId, TCHAR* keyName);
This abstract function is a public member of the IAcadBaseObjectImpl class. Your COM wrapper class inherits IAcadBaseObjectImpl through either IAcadObjectDispatchImpl or IAcadEntityDispatchImpl. CreateNewObject must be overridden in order to add default objects to the database.
Implement the CreateNewObject() function and any other object-specific or entity-specific functions.
The following example shows the implementation of CreateNewObject() from AsdkSquareWrapper:
HRESULT CAsdkSquareWrapper::CreateNewObject( AcDbObjectId& objId, AcDbObjectId& ownerId, TCHAR* keyName) { try { AcAxDocLock docLock(ownerId, AcAxDocLock::kNormal); Acad::ErrorStatus es; AcDbObjectPointer<AsdkSquare> pSq; if((es = pSq.create()) != Acad::eOk) throw es; AcDbDatabase* pDb = ownerId.database(); pSq->setDatabaseDefaults(pDb); AcDbBlockTableRecordPointer pBlockTableRecord(ownerId, AcDb::kForWrite); if((es = pBlockTableRecord.openStatus()) != Acad::eOk) throw es; if((es = pBlockTableRecord-> appendAcDbEntity(objId, pSq.object())) != Acad::eOk) throw es; } catch(const Acad::ErrorStatus) { //To become more sophisticated // return Error(L"Failed to create square", IID_IAsdkSquareWrapper, E_FAIL); } return S_OK; }
Add the desired ActiveX methods and properties to your wrapper class as described in To expose functionality through ActiveX.
In order for your objects' Automation interfaces to be defined correctly, you must revise the generated Interface Definition Language (IDL) file.
In the IDL file, change the interface derivation for your COM object from IDispatch to IAcadObject for a custom object, or to IAcadEntity for a custom entity. Here is an example from the AsdkSquareLib.idl sample file:
interface IAsdkSquareWrapper : IAcadEntity
Add the following code after importlib stdole32.tlb and importlib stdole2.tlb:
importlib("acax24enu.tlb"); // revise the path to match your
// own AutoCAD installation
Make sure you substitute the path that matches your AutoCAD installation.
In the section of the IDL file that corresponds to your wrapper coclass, add [source] interface IAcadObjectEvents; after the [default] line in order to support events.
Move the acax24enu.tlb section to the top of the IDL file, and move your custom object code so that it is within that section.
The IDL file now appears similar to the following code:
import "oaidl.idl"; import "ocidl.idl"; [ uuid(800F70A1-6DE9-11D2-A7A6-0060B0872457), version(1.0), helpstring("AsdkSquareLib 1.0 Type Library") ] library ASDKSQUARELIBLib { importlib("stdole32.tlb"); importlib("stdole2.tlb"); importlib("acax23enu.tlb"); [ object, uuid(800F70AD-6DE9-11D2-A7A6-0060B0872457), dual, helpstring("IAsdkSquareWrapper Interface"), pointer_default(unique) ] interface IAsdkSquareWrapper : IAcadEntity { [propget, id(1), helpstring("property Number")] HRESULT Number([out, retval] short *pVal); [propput, id(1), helpstring("property Number")] HRESULT Number([in] short newVal); }; [ uuid(800F70AE-6DE9-11D2-A7A6-0060B0872457), helpstring("AsdkSquareWrapper Class") ] coclass AsdkSquareWrapper { [default] interface IAsdkSquareWrapper; [source] interface IAcadObjectEvents; }; };
Next, make sure that your ObjectARX component implements the necessary overrides to support ActiveX Automation. If you are building separate COM and ObjectARX DLLs, switch to the ObjectARX project to perform the next procedure.
The AutoCAD Properties palette uses the getClassID() function to retrieve your custom entity's type information. See Properties Palette API for information on implementing Properties palette functionality. If you do not override getClassID() as described below, the Properties palette displays only base class information for your custom entity. However, if you override getClassID() but do not implement OPM interfaces for the custom entity, the Properties palette cannot display either your own class information or the base class data. See Obtaining a CLSID for a Custom Class for more information on getClassID().
In every ObjectARX-based class being wrapped, override the getClassID() function:
Acad::ErrorStatus AcDbMyClass::getClassID(CLSID* pClsid) const { *pClsid = CLSID_WrapperClass; // replace CLSID_WrapperClass with // your COM class CLSID return Acad::eOk; }
In each file that contains an override for getClassId(), include the necessary COM header files, as well as the compiler-generated ID file:
#include <objbase.h> #include <initguid.h> #include "library_i.c" // File containing definitions of the // IIDs and CLSIDs for the COM project. // “library” is replaced by your COM project // name. This file resides in your COM // project directory.
Build and register the COM application according to the steps in Building and Registering a COM DLL. If you are building separate COM and ObjectARX or ObjectDBX ™ DLLs, build the ObjectARX or ObjectDBX module before building the COM application.