getting started with objectarx - welcome | augi - · pdf fileobjectarx® is the most...
TRANSCRIPT
1
Getting Started with ObjectARXTom Stoeckel
ObjectARX® is the most versatile and powerful programming interface for developing new commands and applications to customize and extend AutoCAD®. This course will introduce you to the basics of ObjectARX and its classes. It will provide an overview of what ObjectARX is all about, how it works, some of things you can expect to do with it and what you'll need to get started.
CP11-4
2
Getting Started with ObjectARX
Your instructor – Tom Stoeckel• Autodesk programmer for 6 years• Express Tools and AutoCAD• Battman, Layer Translator• Digital Signatures, Reference Manager• Customizing AutoCAD since Release 9
Getting Started with ObjectARX
This is an INTRODUCTION to ObjectARXSome knowledge of C++ is assumedA chance for info later in the week• CP43-1 – December 5th @ 11:30am• Beginning ARX for the LISP and VBA programmer• Randy Kintzley
3
Housekeeping
Class MaterialsBreaksQuestionsSession Evaluation Form
My Objective
You should know …• Some basics about ObjectARX• How to setup and use the ObjectARX SDK• Where to find help and reference materials• How to setup and use your compiler• How to create an ObjectARX project• Q&A
4
What is ObjectARX?
ARX (AutoCAD Runtime eXtension)• A set of object oriented C++ libraries• Comprehensive API• Hundreds of classes• Thousands of unique member functions
Advantages to ObjectARX
New objects can be added to AutoCAD and existing programs can work with them right away!Performance - Speed of executionNotification of eventsProvides a deep level of access into the system - the same as used by Autodesk themselvesDatabase, operator interface, events
5
Downloading the ObjectARX SDK
Free for downloading• www.autodesk.com/developautocad• www.autodesk.com/objectarx• www.objectarx.com
Reference Materials
ObjectARX SDK HelpAutodesk Developer Network (ADN)• Free - www.autodesk.com/developautocad• Membership - www.autodesk.com/joinadn
• Access to lots of Autodesk software • Beta releases (NDA)• Direct e-mail support • On-line access to samples and solutions • Invitations to ADN Technical Conferences• Opportunities to attend API training classes
Newsgroups• news://discussion.autodesk.com/autodesk.autocad.objectarx
6
Compiler Requirements
If developing for AutoCAD 2004 • Microsoft® Windows® XP (Professional or Home), Windows
2000, or Windows NT® 4.0 (SP6a or later) • Microsoft Visual C++® version 7.0
Visual Studio.NET 2003 (VC7.1) is NOT supported for ObjectARX development with AutoCAD 2004.Since Microsoft no longer sells Visual Studio .NET 2002 (VC7.0) directly, if you don’t already own this version, the alternative is to purchase the Visual Studio .NET 2003, and downgrade to 2002. Information on downgrading can be found athttp://msdn.microsoft.com/vstudio/previous/downgrade.aspx
Compiler Requirements
If developing for AutoCAD 2002, 2000i or 2000• Microsoft® Windows® NT 4.0 or Microsoft® Windows® 2000
• Microsoft Visual C++® version 6.0
7
Integrating the SDK into the compiler environment
Add the path to the SDK include and library directories to the list of Visual Studio search folders.Tools->Options menuProjects->VC++ Directories
Primary ObjectARX Libraries
AcRx• System level routines (initialization, linking, registration, etc)
AcEd• Editor services (monitoring and notification)• New AutoCAD command (defining and registering)
AcDb• Database definitions for all geometry and table objects• Query, manipulation and creation
AcGi• Graphic interface, drawing entities
AcGe• 2D and 3D geometry elements and geometry data manipulation
AdUi/AcUi• MFC derived controls
8
Linking Requirements
All ObjectARX applications must link with acad.lib and rxapi.libMost will also require acdb16.lib so just include it as well
Additional libs required for classes:• AcRx, AcDb and AcGi - None• AcEd - acedapi.lib• AcGe - acge16.lib• AdUi - adui16.lib• AcUi - adui16.lib and acui16.lib • COM - axdb16.lib
How ObjectARX works
ObjectARX is supplied as a set of libraries.ObjectARX programs are DLLs called by AutoCAD.AutoCAD starts an ObjectARX program • when loading initially• when loaded by another ARX module• when loaded using the command ARXLOAD
9
How ObjectARX works (cont’d)
After loading,• AutoCAD calls a standard entry point• Sends a code that tells the module to initialize• Sends other codes as needed
• new drawing load• AutoLISP subr request• drawing saved
ObjectARX
Linking up with AutoCAD• ARX module is loaded• AutoCAD calls the “entry point”
• acrxEntryPoint()• required in every ObjectARX program
First call is to initialize the interface• kInitAppMsg
10
Messages
kInitAppMsg - initializekUnloadAppMsg - unloadkLoadDwgMsg - new drawing loadedkUnloadDwgMsg - drawing unloadedKInvkSubrMsg - from AutoLISPKEndMsg - endkQuitMsg - quit
Messages
The “k” names are constants set to integers.During initialization it is time to establish communication with AutoCAD.• AutoCAD may NOT be all the way up!• DO NOT run commands or expect entities to exist.• DO establish new commands and reactor linkages
to your functions.
11
Messages
The second message into your ARX module will be to inform you that a drawing is loaded.Now AutoCAD is ready to process commands, allow for entity linkages to reactors and so forth.Init message will be sent once, load message may be sent multiple times.
The AutoCAD Editor
The AcEd class has many services which include:• Command stack utilities• Event notification• AcEdJig (used for interactive dragging)
There are two ways to register commands in ARX• acedDefun()• acedRegCmds->addCommand()
12
Command Registration
acedDefun()
Registers your commands as a LISP functionInvoked using (command)Register during kLoadDwgMsg requestMust be removed with acedUndef() during kUnloadDwgMsg request
Command Registration (cont’d)
acedRegCmds->addCommand()
Registers your commands as “native” commands on the AutoCAD command stack with all the other AutoCAD commandsARX registered commands can be invoked using LISP (command) or acedCommand()
13
AcDbLibrary
An AutoCAD drawing file is a collection of objects stored in a databaseBy default a new database contains• 9 symbol tables• Named object dictionary• 200+ header variables (not objects)
AcDb classes give you access to these objects
AcDb Functions
Get the current database for the AutoCAD edit session• acdbHostApplicationServices()->workingDatabase()
Multiple databases can be loaded at one time with• readDwgFile()
• The AutoCAD editor can only work with the file that it has opened
• Since a handle is only unique for a single database, an object ID is automatically created for each object in the session
14
AcDbDatabase
Is a collection of objects• Each with a unique identifier that is guaranteed for the context
of that drawing• Entities
• Graphical objects• Objects
• Non-graphical• A fixed set of symbol tables
• Layer, Linetype, Block, etc.• Dictionaries
• Named object dictionary, Groups, etc.
Object IDs
Handle• Object stored on disk• Never changes and is never reused in the same drawing• Use when the ID must persist between sessions• Slower than ObjectID because they are stored as strings and
string comparison is slowObjectID• Assigned when the drawing is opened• Will be different from session to session
Object Pointer• Assigned when an object is opened in memory• Only valid while the object is open
15
ObjectID
The system creates an object ID for each object in the database when it is read into memoryWith the object ID, you can get a pointer to the actual database object and modify itAlways use an object ID if you can as they are faster than handlesAutomatically translated to handles on filing operations
Identifying an Object
There are several ways to determine what kind of object is open• desc
• Returns the class descriptor• cast
• Returns an object of the specified type or NULLAcDbEllipse* ellipseEntity = AcDbEllipse::cast(curEntity);
• isKindOf• Object belongs to or is derived from the specified classpObj->isKindOf(AcDbText::desc()
• isA()• Returns the class descriptor object of an object whose
class is unknown pObj->isA() == AcDbViewTableRecord::desc()
16
Working with Database Resident Objects
Creating New DRO• Create an instance of the objects’ class• Modify its state using it’s member functions• Add it to the proper table or dictionary• Close or cancel the object
Modify or Query a DRO• Open the object using the objectID• Modify or query the object using the objects member functions• Close or cancel the object
Creating a New ObjectAcGePoint3d p1, p2;p1(0) = 1.0; p1(1) = 2.0; p1(2) = 0.0;p2(0) = 2.5; p2(1) = 4.25; p2(2) = 1.0;
AcDbLine *pLine = new AcDbLine(p1, p2);
AcDbBlockTable *pBTable;acdbHostApplicationServices()->workingDatabase->getSymbolTable(pBTable,
AcDB::kForRead);
AcDbBlockTableRecord *pBRec;pBTable->getAt(ACDB_MODEL_SPACE, pBRec, AcDb::kForWrite);pBTable->close();
AcDbObjectId lineID;pBRec->appendAcDbEntity(lineID, pLine);
pBRec->close();pLine->close();
17
Opening Database Resident Objects
Get a pointer to the actual object with acdbOpenObject()
acdbOpenObject(pLayer, objIdCurLayer, AcDb::kForRead);
Specify which mode of access you want• kForRead - up to 256 at one time on one object• kForWrite – only 1 at a time per object
Open for read then upgradeOpen() for write
Object State Query/Manipulation
You can choose to open erased objects, the default is falseUse the member functions to directly access object’s state (data)When looking for functions in header files or the help files, don’t forget that some member functions will be inherited from base classes
18
Ending Object Query/Manipulation
When Finished• close()• cancel()
Recording is automatic from open() to close()Undo playback occurs automatically when cancel() is called instead of close()Use Smart Pointers (dbobjptr.h)
Basic Error Handling in ObjectARX
Always check your return values before proceedingDo not assume anythingAcad::ErrorStatusCheck for NULL valuesUse acadErrorStatusText()
Return useful error information from your own functions
19
Memory Management - General
Close everything you openDelete your iteratorsUse Smart Pointers when possible• include “dbobjptr.h”• Takes some of the burden off of the developer to keep track of everything
Memory Management - Objects
The responsibility of memory management changes during the life cycle of an object.When you create an instance of an object with new, it allocates memory from AutoCAD’s drawing database heap.If your application never adds the object to the database YOU are responsible for freeing that memory with delete.If the object is added to the database AutoCAD is now responsible for that memory and you should NOT delete it. Doing so would very likely cause AutoCAD to terminate.
20
Memory Management - Strings
char* strings returned by the SDK are always allocated from the AutoCAD heapThese strings should be de-allocated with acutDelString()
char* pName = NULL;
if (pLayout->getLayoutName(pName) == Acad::eOk)
acutDelString(pName);
Memory Management - Strings
const char* strings returned by the SDK are the responsibility of AutoCAD and should not be de-allocated
const char* pName;
pLayout->getLayoutName(pName);
When in doubt, check the SDK help for the function in question
21
Container Objects
Symbol tables• Fixed set, you can not add or delete (only purge)• Contains instances of symbol table records
• Layers• Linetypes• Blocks
• Dictionaries• Generic container for any type of object• Can create your own
Special Symbol Table
Block Table• All entities are owned by block table records• Has three default records
• *MODEL_SPACE• *PAPER_SPACE0• *PAPER_SPACE1
• Entities must be added one of these BTR’s to be visible in AutoCAD editor
22
AcDbDictionary Definition
Database resident objectMaintains a map between text strings and database objectsBecomes the owner of the added objectsAttaches itself to the object as a persistent reactor so the dictionary can be notified when the object is erased
Iterating Through Object Containers
Objects that use iterators• Symbol tables• Block table records• Dictionaries• Polylines• Block references (inserts)
• Only useful when attributes are present
23
Iterator Protocol
Iterators can return erased as well as unerased object/entitiesIterators can start at the beginning or end of the container and walk forward or backwardStep direction can be changed any timeIterators also provide a “seek” function to find a specific object (by objectID or by object address)
Iterator Protocol
Inconsistency of iterator protocol reflects differences in underlying containersObtaining, using, deleting iterators• Use the newIterator() function (when it exists) to create an iterator object and get a pointer to it
• Use the iterator member functions to walk the list of objects in the container
• Delete the iterator object when finished• Close the container object once the iterator is deleted
24
Navigating Through Symbol Tables
AcDbSymbolTableIterator• AcDbLinetypeTableIterator• AcDbBlockTableIterator
• AcDbBlockTableRecordIterator• AcDbLayerTableIterator• AcDbTextStyleIterator
Reacting to Events
Events are when something happensProcess controls are examples of event driven systems.Reacting to seemingly random events may seem complicated, but it really isn’t and it is common in many applications.
25
Reactor
A reactor is something that reacts to a notification.ObjectARX provides a set of standard reactors that can be used.You can have any number of reactors for a given notification type.There are five reactor categories in ARX
Reactor types
General databaseSpecific objectCommand activitiesObjectARX monitoringGeneral purpose transaction
26
Notification Definition
Every object maintains a list of reactors itselfTransient Reactors• Commonly known as event notification, to be used when you
want to monitor things that are happening during the edit session
Persistent Reactors• A way to make your object intelligent, your custom object can
react to whatever you want• Other object being moved or copied• Environment changes
Transient vs. Persistent
Transient Reactor• Is an instance of a class• Not saved from edit session to session• Not copied with the objects
Persistent Reactor• Is an objectID of a database resident object• Can be derived from any type AcDbObject• Stay with the drawing• Copied when object is copied.
27
Editor Reactors – Notification Functions
commandWillStart()commandEnded()commandCancelled()beginSave()saveComplete()etc.
Database Reactors – Notification Functions
objectAppended()objectModified()objectErased()objectUnappended()objectReappended()etc.
28
Object Reactors – Notification Functions
copied()openedForModify()modified()modifiedGraphics()modifiedXData()erased()objectClosed()
Adding a Reactor
Finding the name to use is often the hardest step!Three steps• Derive from the appropriate base class• Override member functions for notifications you
wish to receive• Instantiate an object of your derived class• Call addReactor() to addPersistentReactor()
member of the notifier object, passing it either a pointer to or an objectID of the reactor object
No VETO power!
29
Removing a Reactor
Remove reactors by calling removeReactor() or removePersistentReactor() function of the notifier object, passing a pointer to the reactor object.When your application unloads, it should remove all transient reactors it plantedAutoCAD will take care of deleting persistent reactors because they are database objects
Transient Reactor Details
The reactor object is directly called by the notifier objectCan be added to/removed from watched object in any open modeAddition/removal not subject to UNDOTransient reactor attachments are not copied when an object is copied
30
Persistent Reactors Details
Persistent reactors can only be derived from AcDbObject and classes derived from it (i.e. AcDbEntity, Custom Objects)Reactor objects must be added o the database and given an owner so they will persistCan only be added to/removed from watched object when open from writeThis object must be added to the database and given an owner, preferably a container object (i.e. dictionary)When an object is copied, any persistent reactors attached to the object are copied as well.
Notification Restrictions
While object is notifying it is in a read-only stateYou are not able to modify it until the end of the commit process which can be checked with• objectClosed()• transactionEnded()
Notification is a read-only affair: No Veto!• (but workarounds…)
31
“Undoing” an Event
No veto so how do I “undo” a change that I’ve been notified of?• Cache state at time of openedForModify()• When objectClosed() notification occurs, open object for write and change state back (watch out for infinite notification loop)
• Or put reactors on editor for lispEnded and commandEnded. When one of these notifications comes through then open object and change it back
Custom Objects
Why create a new object?• For specific applications• For specific needs in your programs• For the fun of it?
New objects are complete class definitions• You must explain everything about them to
AutoCAD!
32
Custom Objects
There are three macros that are available in ObjectARX that make the creation of new objects easy.• ACRX_DXF_DEFINE_MEMBERS• ACRX_DEFINE_MEMBERS• ACRX_NO_CONS_DEFINE_MEMBERS
The hard part is overriding all the functions
Derive from Existing Class
There are three classes to derive from that are used most frequently• AcDbObject• AcDbEntity• AcDbCurve
33
Why not use existing objects?
There is little you can do to improve these objects themselvesThey already work! You want to make new objects.
Save and Load
Not only do you have to define how to manipulate and draw the objects you must also define how to save and load the object.
File storage is important - this where you• Set up group codes for the data • Define how the object is drawn if your program is
not available to control them
34
Save and Load
dwgOutFields - get data from the properties and output them with group codes.• writeItem
dwgInFields - get data from file and put them in the properties of the custom object.• readItem
Draw the Object
WorldDraw - draw in world viewViewportDraw - draw in a view portsaveAs - draw when saving to a file• This is what object will look like when your
ObjectARX program is NOT loaded.
AcGi function library is used to draw the objects
35
Proxy objects
Proxies occur when your ObjectARX program is not loaded.• These used to be called Zombies - a much more
descriptive term!• worldDraw or SaveAs is used to define what the
object will look like - this information is saved in the DWG outside of your control.
Creating a simple ObjectARX project
From the File pull down menu of Visual C++ .NET, select New and Project....Click on the VC++ Projects node in the Project Typestree on the New Project dialog that appears.Select Win32 Project in the list of templates.Enter the desired project name in the Name edit box. Set the location to the folder where you want your project to be stored, then click OK. This will invoke the Win 32 Application Wizard dialog.Select Application Settings tab on the wizard. Select DLL for the Application type option.Click on Finish to create the project.
36
Creating a new ObjectARX project
Right click on the project node in the Solution explorer and select the Properties in the right-click menu. This brings up the property pages dialog for the project.In the Configuration drop-down list, select All Configurations. This will ensure that the changes we make are applied to all theconfigurations. Select the node C/C++ -> General and set Detect 64-Bit Portability Issues to No. Click Apply button to apply the changes. Select the node C/C++ -> Code Generation. Select the item Runtime Library in the list. Assign the property Multi-threaded DLL (/MD), by selecting the property from the drop-down list.Select the node Linker -> Input. In the Additional Dependenciesitem, add the following libraries: "rxapi.lib acdb16.lib acge16.lib acad.lib acedapi.lib"Next, select the node Linker -> General. In the Output File item, change the extension of the output file from ".dll" to ".arx".
Create the definition (.DEF) file
Used to provide linkage to AutoCAD’s ObjectARX handling system
From the Project pull down menu, select Add New ItemIn the Add New Item dialog, select item Def File (.def). Enter the name of your project in the Name edit box. Click "Open" Add the following information to an EXPORTS section in the new file. All ObjectARX applications have to export at least two functions
EXPORTSacrxEntryPoint PRIVATEacrxGetApiVersion PRIVATE
37
Header Files
Include necessary header files
#include <aced.h>
#include <rxregsvc.h>
Add header files as needed by ObjectARX classes and functions that you use in your applicationSee your SDK help to determine which headers are needed
Add Init and Unload functions
These will be referenced by acrxEntryPoint()
initApp()• Called by AutoCAD when our application is loaded
unloadApp()• Called when our application is unloaded.
38
Add Init and Unload functionsvoid initApp();void unloadApp();
void initApp(){ // register a command with the AutoCAD command mechanismacedRegCmds->addCommand("HELLOWORLD_COMMANDS","Hello","Bonjour",ACRX_CMD_TRANSPARENT,helloWorld);
}
void unloadApp(){ acedRegCmds->removeGroup("HELLOWORLD_COMMANDS");
}
Add the main function body
This function simply prints a message at the AutoCAD command line
void helloWorld();
void helloWorld(){ acutPrintf("\nHello World!");
}
39
acrxEntryPoint()
This is the main program moduleAutoCAD expects to find one in every ARX appMessages are sent directly to your applicationSet up and shut down control handled here
extern "C" AcRx::AppRetCodeacrxEntryPoint(AcRx::AppMsgCode msg, void* appId){switch(msg) {
case AcRx::kInitAppMsg:// Allow application to be unloaded. Without this statement, AutoCAD will// not allow the application to be unloaded except on AutoCAD exit.//acrxUnlockApplication(appId);// Register application as MDI aware. Without this statement, AutoCAD// will switch to SDI mode when loading the application.//acrxRegisterAppMDIAware(appId);initApp();break;
case AcRx::kUnloadAppMsg:unloadApp();break;
case AcRx::kLoadDwgMsg:// initialize lisp functions herebreak;
case AcRx::kUnloadDwgMsg:// remove lisp functions herebreak;
}return AcRx::kRetOK;
}
40
Macros to simplify common operations
Consolidate several lines of code into oneAdd these to a header file in your project.
Check if the Acad::ErrorStatus is eOk
inline intEOK(Acad::ErrorStatus arg){return arg == Acad::eOk;
}
Usage
Acad::ErrorStatus es;es = acdbOpenObject(pBlockRef, blkRefIds[i], AcDb::kForWrite);if (!EOK(es))break;
Macros to simplify common operationsSame as above only display an alert dialog when things aren’t eOk
#define EOKM(arg) \((arg == Acad::eOk) ? true : Mutter(__FILE__, __LINE__, arg))
inline boolMutter (char *file, int line, Acad::ErrorStatus arg){char buf[1024];wsprintf(buf, "!%s@%d: %s", file, line, acadErrorStatusText(arg));acedAlert(buf);return false;
}
Usage
Acad::ErrorStatus es;es = acdbOpenObject(pBlockRef, blkRefIds[i], AcDb::kForWrite);if (!EOKM(es))break;
41
Macros to simplify common operations
Get the working database without all that typing
inline AcDbDatabase *
CURDB()
{
return acdbHostApplicationServices()->workingDatabase();
}
Usage:
AcDbBlockTablePointer pBlockTable(CURDB(), AcDb::kForRead);
You get the idea!
ObjectARX Summary
It is not difficult to program in ObjectARXOpens a wide world of possibilities
The next step...
42
The next step
Learn C/C++?
More information?
Learn by doing
Thank You
Turn in your session evaluation forms as you leaveEmail: [email protected]
43