This method uses MFC and the Visual C++ Add Class from Typelib Wizard to read the AutoCAD type library (acax24enu.tlb). The sample program uses the COM ActiveX Automation interfaces of AutoCAD to create a circle in model space. The following sections provide procedures to guide you through the program setup and implementation:
To begin adding specific ObjectARX functionality, you must adjust the project settings and add boilerplate code.
Add the appropriate values to the project properties to make the project build as an ObjectARX program. Be sure that the ObjectARX \inc and \lib directories are in the project's search path. This program needs to link with the following libraries:
acad.lib
acdb24.lib
rxapi.lib
In your project's definitions (DEF) file, add the following lines to the EXPORTS section:
acrxEntryPoint PRIVATE acrxGetApiVersion PRIVATE
Open the AsdkMfcComSamp.cpp source file and add the following code to make the program ObjectARX compatible:
#include <rxregsvc.h> #include <aced.h> #include <rxmfcapi.h> static void initApp() { acedRegCmds->addCommand( "ASDK_MFC_COM", "AsdkMfcComCircle", "MfcComCircle", ACRX_CMD_MODAL, addCircleThroughMfcCom); } static void unloadApp() { acedRegCmds->removeGroup("ASDK_MFC_COM"); } 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(); break; default: break; } return AcRx::kRetOK; }
Stub in your new AutoCAD command handler function by adding the following code to the AsdkMfcComSamp.cpp source file:
void addCircleThroughMfcCom() { }
In order to build your project without linker warnings, you must make MFC aware that your debug project links to libraries that are built with the release MFC libraries. This is accomplished by suspending the definition of the debug symbol only while the compiler processes the MFC header files.
In the generated stdafx.h file, before the first MFC include statement (usually #include <afxwin.h>),add the following code:
#ifdef _DEBUG #undef _DEBUG #endif
From the Build menu, select Build AsdkMfcComSamp to verify that your project setup is correct.
Your project should build successfully, but at this point it doesn't do anything. The next step is to implement the command handler with ActiveX Automation calls.
First, you must decide which interfaces are necessary. To add a new circle to model space, the IAcadApplication, IAcadDocument, and IAcadModelSpace interfaces are required. You use the AutoCAD type library, acax24enu.tlb, to get the definitions of these interfaces, as shown in the next procedure.
Now that you have imported the necessary interfaces, you are ready to implement the command-handling function.
CAcadApplication IApp; CAcadDocument IDoc; CAcadModelSpace IMSpace;
Use the acedGetAcadWinApp() function to obtain the CWinApp MFC object for AutoCAD, and call the GetIDispatch method:
IDispatch *pDisp = acedGetAcadWinApp()-> GetIDispatch(TRUE);
Once you have the IDispatch object, attach it to the locally defined CAcadApplication object and make sure that AutoCAD is visible:
IApp.AttachDispatch(pDisp); IApp.put_Visible(true);
Obtain the active document dispatch and attach it to the locally defined CAcadDocument object:
pDisp = IApp.get_ActiveDocument(); IDoc.AttachDispatch(pDisp);
Query the active document for model space:
pDisp = IDoc.get_ModelSpace(); IMSpace.AttachDispatch(pDisp);
A circle requires a center point and radius. To make this efficient and transparent to different programming languages, the COM interface uses the VARIANT type. A point is stored in a VARIANT as a SAFEARRAY. Add the following code to set up a SAFEARRAY and store it in a VARIANT:
SAFEARRAYBOUND rgsaBound; rgsaBound.lLbound = 0L; rgsaBound.cElements = 3; SAFEARRAY* pStartPoint = NULL; pStartPoint = SafeArrayCreate(VT_R8, 1, &rgsaBound); // X value // long i = 0; double value = 4.0; SafeArrayPutElement(pStartPoint, &i, &value); // Y value // i++; value = 2.0; SafeArrayPutElement(pStartPoint, &i, &value); // Z value // i++; value = 0.0; SafeArrayPutElement(pStartPoint, &i, &value); VARIANT pt1; VariantInit(&pt1); V_VT(&pt1) = VT_ARRAY | VT_R8; V_ARRAY(&pt1) = pStartPoint;
Call the AddCircle method from the CAcadModelSpace object:
IMSpace.AddCircle(pt1, 2.0);
Here is the finished function, with clean-up code and exception handling added:
void addCircleThroughMfcCom() { TRY { CAcadApplication IApp; CAcadDocument IDoc; CAcadModelSpace IMSpace; IDispatch *pDisp = acedGetAcadWinApp()-> GetIDispatch(TRUE); // AddRef is called on the // pointer IApp.AttachDispatch(pDisp); // does not call AddRef() IApp.put_Visible(true); pDisp = IApp.get_ActiveDocument(); // AddRef is called IDoc.AttachDispatch(pDisp); pDisp = IDoc.get_ModelSpace(); // AddRef is called IMSpace.AttachDispatch(pDisp); SAFEARRAYBOUND rgsaBound; rgsaBound.lLbound = 0L; rgsaBound.cElements = 3; SAFEARRAY* pStartPoint = NULL; pStartPoint = SafeArrayCreate(VT_R8, 1, &rgsaBound); // X value long i = 0; double value = 4.0; SafeArrayPutElement(pStartPoint, &i, &value); // Y value i++; value = 2.0; SafeArrayPutElement(pStartPoint, &i, &value); // Z value i++; value = 0.0; SafeArrayPutElement(pStartPoint, &i, &value); VARIANT pt1; VariantInit(&pt1); V_VT(&pt1) = VT_ARRAY | VT_R8; V_ARRAY(&pt1) = pStartPoint; IMSpace.AddCircle(pt1, 2.0); VariantClear(&pt1); // Release() is called implicitly on the local objects } CATCH(COleDispatchException,e) { e->ReportError(); e->Delete(); } END_CATCH; }
Rebuild your project.
Load the ARX file in AutoCAD, and enter MFCCOMCIRCLE at the command line to test your code.
COM programmers are normally required to call Release() on any interface pointer for which AddRef() previously has been called. In the example above, MFC relieves you of this responsibility by internally calling Release() on its local interface wrapper objects. However, you should be mindful of the need to release COM interface pointers when you are finished using them. The technique of explicitly releasing interface pointers is demonstrated in the following procedure.