Wednesday, February 23, 2005

Class 3b - Minimum application using ARXWizard

Hello,

On previous class I have presented the step by step way to create a minimum application by hand. Of course there is a easier way to do that but I think is very important that you understand correctly things that are behind the scenes.

This time we will use the ARXWizard tool which is provided by Autodesk through ObjectARX SDK. If you go to the \Utils folder you will find the install program. Go ahead, install it and allow Live Update to run at the first time. Do this with your Visual Studio .NET closed.

After you install it, open Visual Studio.NET, open File menu and start a New Project. The following dialog will appear and you will find a new node inside Visual C++ Projects folder which is called Autodesk. Select this node and the ObjectARX/DBX/OMF Project icon will appear at the right side as following:




Fill out the Name field and specify the desired location to create the new project. Click OK to continue. The following dialog will appear:



This dialog presents the steps to setup your new project. The first page, called Overview, shows some information and give you the opportunity to inform your RDS (Registered Developer Symbol). This label will be used to prefix anything that your code could implement and could conflict with other third-party applications. To allow this prefix to be unique, Autodesk provides (through ADN subscriptions) a way to register your prefix and inform other ADN members. Even you are note an ADN member you should create your own RDS. Use your initials, your 3 name first chars or any other name you find clear and useful.

The next step is to choose your desired Application Type. As I have mentioned before, ARXWizard suggests the ARX / DBX types which are basically the separation of Interfaces and Custom Classes. More details about the main differences between ARX and DBX can be found at ObjectARX documentation. This time we will choose the ObjectARX option as follows:



The next step is about Additional SDK Support which allows you to extend basic ObjectARX features to an specific Autodesk vertical. There are two options:

  • OMF Support: This is the SDK extension for Autodesk Architectural Desktop (aka ADT) which contains specific features that could be used if you plan to develop an ObjectARX application to run inside ADT;
  • MAP API Support: This is the SDK extension for Autodesk MAP which contains extra features to be used if you plan to develop a MAP ObjectARX application.

In our case, we will develop an ObjectARX application targeting plain (or vanilla) AutoCAD so leave both blank.



The next step is to specify MFC Support. As I mentioned before we will use MFC Extension DLL project type. This dialog also offers the option to enable AutoCAD MFC Extension Support which will allow you to use specific AutoCAD controls like LineType combo boxes, Color combo boxes, Dockable dialogs, etc. This is pretty handy once those controls are not so simple to implement from scratch. Select Extension DLL and enabled AutoCAD MFC Support:



The last step is dedicated to COM related stuff. ObjectARX supports COM implementations on both Server and Client sides. As COM programming is very complex and is beyond this course scope so I will not cover it.



Leave the options on the Not a COM Server and None. Click Finish to proceed.

Now you can open the project files and see what the ARXWizard has done for you. There are a lot of differences between the project we have created on previous class and the present project because ARXWizard use different implementations using handy classes. We will cover these features several times with our upcoming samples on the next classes.

Compile and Build the project and try to load the resulting ObjectARX application inside AutoCAD. You probably will be able to successfully load it.

Thursday, February 17, 2005

Class 3a - Minimum application

Hello,

On this class we will implement the minimum ObjectARX application without use the ARXWizard. To do that we will need to create the Visual C++ project from scratch and perform some tuning on project settings.

To begin, open your Microsoft Visual C++ .NET 2002. Open File menu, then choose New and New Project. The following dialog will appear (note that this dialog can change a little bit depending on what add-on your have installed):



On this dialog, choose Visual C++ Projects tree node and, on the right portion select MFC DLL template. After that, specify the name and location you would like to use for this project. Click OK to continue.

After click OK the following dialog will be displayed. This dialog has two steps (in this case). The first step, called Overview, just confirm what you have entered before.



Clicking on the Application Settings step, the following page will appear inside this dialog:



Now we will choose the MFC extension DLL that is the most adequate DLL type to build ObjectARX applications. Note that the use of MFC is not an obligation. You can build ObjectARX applications without MFC but I strongly recommend you to always use MFC because if you don't need MFC now you probably will need it in a near future.

I would like to avoid more technical discussions on this subject because this is not our focus on this course. MFC is a huge and rich library that will avoid several lines of code and will make your application safe and easy to manage. Click Finish to continue.

After clicking Finish Visual C++ will create the MFC DLL project files for you with basic implementation of some features. Remember, this is just a minimum application and we will only make a few things to turn it ready to compile, build and load into AutoCAD.

The Visual C++ environment is very intuitive and I guess you will not face much trouble to learn how to use it. Basically it has a project management area (default placed at left side), an editor area (placed at the right portion) and the command / monitor area which is placed below. The project management area uses a tab dialog bar to provide tools like Solution Explorer, Resource View and Class View among many others.

Select the Solution Explorer tab and you will see your project files, organized using a tree. This explorer can handle multiple projects but only one can be the default which has its name in bold font.

Now we will need to change some basic settings on our Visual Studio environment to allow us to compile and link ObjectARX application. As I said on previous classes, to build the application, which is a DLL, we will need to compile using the provided ObjectARX headers (.H files) and to link with ObjectARX libraries (.LIB files). The easiest way to do this is to change the global Options of Visual Studio. This will affect all projects and you won't need to do this again for new projects.

Open the Tools menu and select Options (the last entry). The following dialog will appear. Select Projects and then VC++ Directories. On the Show directories for field, select Include files. Below will appear a list of the include directories that Visual Studio already has and we will add our ObjectARX inc path which contains the desired .H files. Click on the folder icon and click on the ellipsis button and search for the inc path (in my case, it is placed at C:\ObjectARX 2004\inc).



Don't click OK. Now we need to add the library files directory. Select Library files on the Show directories for field. Repeat the above procedure to add a path but this time you will add the lib path (in my case, C:\ObjectARX 2004\lib). Click OK to finish.



Now we need to configure our project. This will require some project settings change and some code typing. First, we will change the project settings. Right click the project name inside Solution Explorer and select Properties. The following dialog will appear. Select, on the Configuration field, All Configurations. This will allow us to change both Debug* and Release* settings at the same time.

On the Configuration Properties node, select C/C++ and Code Generation. The right portion of this dialog will display a list with several properties. Select the Runtime Library entry and chance its value to Multi-threaded DLL. This is a requirement to make our DLL compatible with AutoCAD environment.



Now, select the Linker node and General. On the Output File entry change the extension name from DLL to ARX. Note that Visual Studio use several macros (those names with a $ at beginning) to allow easy and flexible path configuration.



Still inside Linker node, select Input. Here we will add those libraries our application will use. This will depend on what features you are using inside your ObjectARX application. In this case, we will add just the basic two libraries called rxapi.lib and acdb16.lib.

Select the Additional Dependencies entry and click on ellipsis button. Type the two previously mentioned files. These libraries are located at lib folder. Remember that on previous classes I have talked about the features each library has built in.



Click OK to close Project Properties dialog. Now we still need to do some code typing. The first step is to edit the DEF file which is placed at Source Files folder of your project at Solution Explorer. Double click the DEF file and it will appear at the right portion of Visual Studio window. We will need to add the following lines, under the EXPORTS section of this file:

acrxEntryPoint PRIVATE
acrxGetApiVersion PRIVATE


Pay attention to the name between quotes in front of LIBRARY section inside this file. This name must be the same name you have entered on the output file. In other words, if your project generates a ABCD.arx file you need to have LIBRARY "ABCD" inside the DEF file.



The next step is to change our StdAfx.h file which is the key compilation file. We will need to inform Visual Studio to use Release version of MFC libraries when our project is being compiled using the DEBUG directive.

To do that, open the StdAfx.h file which is located at Header Files folder inside Solution Explorer. Before the #include line, insert the following code:

#if defined(_DEBUG) && !defined(_FULLDEBUG_)
#define _DEBUG_WAS_DEFINED
#undef _DEBUG
#pragma
message (" Compiling MFC header files in release mode.")
#endif

Now, scroll to the end of this file and add the following lines to manage the _DEBUG symbol back and to include basic .H files our application will need:
#ifdef _DEBUG_WAS_DEFINED
#define _DEBUG
#undef _DEBUG_WAS_DEFINED
#endif

// ObjectARX Includes
#include "rxregsvc.h"
#include "acutads.h"

The last step is to add our acrxEntryPoint method which is our application start point. Open the CPP file of your application which has the same name that you have set to your project plus the CPP extension. It is placed inside Source Files folder. Open if and scroll down to the end. Add the following lines:

// ObjectARX ENTRYPOINT
extern "C" AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* appId){
switch(msg) {
case AcRx::kInitAppMsg:
acrxUnlockApplication(appId);
acrxRegisterAppMDIAware(appId);
acutPrintf(_T("\nMinimum ObjectARX application loaded!"));
break;
case AcRx::kUnloadAppMsg:
acutPrintf(_T("\nMinimum ObjectARX application
unloaded!"));
break;
}
return AcRx::kRetOK;
}


Now we are ready to build our application. Open Build menu and select Build Solution (or F7 key). Visual Studio will compile and link and build your project. If you have followed all above steps carefully it will generate the application without any error.

Start AutoCAD and run APPLOAD command which will show the following dialog. Browse to your project and you will find the application inside the Debug folder which is the default compilation type. Select it and click Load button. A message will appear at the bottom of this dialog telling you that your ARX was successfully loaded or not!



That's it, your first ObjectARX application is loaded and is running inside AutoCAD!
Next class we will do the same using the ARXWizard. Stay tuned!

Tuesday, February 15, 2005

Appendix A - Debug versus Release

ObjectARX and ObjectBDX applications could be compiled using Debug or Release configurations. For those who are beginners with programming is very important to know what are the differences between these two types of compilation.

When your are developing an application you will pass through several steps before it reaches the deployment phase. These steps are very important to detect bugs inside your application, correct them and make your application as much secure as you can.

When you are on the phase prior to deployment you will probably need to debug your code. The debug tool, using a simplistic point of view, is just a way to follow your application execution mapping what is happening on the execution environment to the corresponding line at your source code. This tool is powerful and essential to troubleshoot your application.

To make this happen, Visual Studio compiles your code adding debug information that will allow it to map events to your source code, show variables, show memory stack, code flowing and much more. This is pretty handy and helps a lot! Matter of fact you can't live without the debug tool. Due that, your resulting application is linked with Debug versions of extensions you are using like MFC. If you deploy your Debug version to your clients they will face trouble to load it because the probably will not have those debug libraries available.

Suppose your application uses the mfc42.dll which is a common situation. When you compile your application using the Debug type it will use the mfc42d.dll which is the debug version of the original DLL. When your client tries to load the application, Windows will search for the required DLL (debug version) which does not exist in that machine and will fail to load.

Worst than deploy Debug version is do ship the debug version of those DLLs your application needs. These DLLs are for development purposes only. Please, don't do that!
There are much more issues involved on this but basically you should follow the following ground rules:
  • Use the Debug compilation for development purposes only;
  • From time to time compile and test your application with Release version because Debug compilation is more robust and may hide some runtime errors that Release version won't;
  • Don't ship debug versions of Windows or third-party libraries except for debug purposes;
  • Use the _DEBUG symbol directive to isolate parts of your code that are only interesting when debugging. For instance, some trace messages are very interesting to you but users will hate to keep seeing them every time.

At the last, debug compiled applications has a higher file size (sometimes almost 5 times greater than Release version).

Thursday, February 10, 2005

Class 3 - Application Overview

Introduction

As I mentioned before, the ObjectARX is actually a DLL. It can be linked with or without MFC extensions. Most of times you would like to link with MFC. Autodesk provides a pretty handy Wizard to allow users to quickly create ObjectARX applications with minimun code effort.

Before we can proceed I would like to clarify the main differences between ObjectARX and ObjectDBX applications. The main idea is to separate Interface and Object Classes to allow the called "Object Enablers". This is not a mandatory but it is a good programming practice and Autodesk made this separation to provide great things like, for instance, open an ADT drawing inside AutoCAD, download the proper enabler and then show those ADT entities correctly inside AutoCAD.

Suppose you need to create an application with a bunch of custom entities and objects. The drawings created with this application will contain these custom objects and if another users try to open this drawing inside AutoCAD and without your applications they will see only Proxy entities. If you would like to allow these users to see your custom entities but don't perform any commands over them you just need to ship de DBX part of your application. This way the user will be able to see your custom entities and perform some limited operations.

When the drawing is saved AutoCAD preserve the custom entity information using the called Proxy entities. This will happen even if the DBX module is not available. The Proxy entities stores the binary data of your custom object and keep that until your application come back.
In other hand, the ARX module of your application will be responsible for the interface. There you should register your commands, create your dialogs, customize menus, etc.

Application Structure

Both ARX and DBX modules must implement an entry point function. This function is responsible to perform messages exchange between AutoCAD and your application. For those who are familiar with old C language it is the substitute of main() function.
This entry point function has a signature as follow:

extern "C" AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt);

A simple implementation of this function is:

extern "C" AcRx::AppRetCode
acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt)
{
switch(msg) {
case AcRx::kInitAppMsg:
break;
case AcRx::kUnloadAppMsg:
break;
default:
break;
}

return AcRx::kRetOK;

}

This function is automatically implemented by the Wizard as you will see later. The first parameter (msg) is the message sent from AutoCAD to your application telling you what is happening. You may receive a "new drawing" message, a "init application" message among many others. These messages are very important to your application and to allow you to react to each desired event to monitor. The second parameter (pkt) is a data package that can be useful in some situations that I would avoid to discuss now (remember, our course is for Dummies). This function must return a value to AutoCAD using AppRetCode which can be kRetOK (common value) or even kRetError which will force AutoCAD to unload your application.

The most relevant point here is to remember that this function is very important and is where your application will begin to execute.

Registering Commands

Probably your application will implement several commands. You can register your commands from the acrxEntryPoint() function when receiving the kInitAppMsg message that represents the event fired by AutoCAD when it loads your application (this can be done by several ways that we will discuss later). Once this message is received, you can call the appropriate methods to register each desired command.

Registered commands must have a Group Name, a Global Name, a Local Name, some flags, a void function pointer and, optionally, some other parameters. Basically the registered command will fire the function you specified. This function must be a void function without any parameters. When the user inside AutoCAD call your command, AutoCAD seek its command stack, find your command and fire your function. That's it!

It is very important that you preceed your commands with a 3 or 4 letters prefix to avoid command colision with other third-party applications. Regarding to the main parameters:
  • Group Name: Allows you to group your common commands to make easier to unload and manage them;
  • Global Name: Your command untranslated name. You should use english names here that is the most used language;
  • Local Name: Your localized command name which represents the translated name;
  • Flags: Can be a combination of several types. The two most important flags are ACRX_CMD_TRANSPARENT and ACRX_CMD_MODAL. They establishes your command behavior that can be transparent (like ZOOM) or modal (like major commands);
  • void function pointer: Here you pass the name of the void function you would like to link with the command. This function will be fired by AutoCAD when the command is invoked.

Once you register your commands you need obviously to unregister when leaving AutoCAD or when your application is unloaded. This can be easily done unregistering all commands by the Group Name. When you recieve the kUnloadAppMsg message is time to remove your commands.

Running your application

Supposing you already compiled your application successfully it is time to load it inside AutoCAD and test your commands. My preferable method to load / unload ObjectARX applications is through the APPLOAD command. It opens a very handy dialog that allows you to browse for the application and load it. It comes also with a Startup Suite briefcase that allows you to automatically load a list of applications when AutoCAD starts.

Once your application is loaded, just fire your commands and enjoy!

I have posted a simple application made by ARXWizard and Visual Studio.NET 2002 (7.0) and ObjectARX 2004. It is called SimpleLine and it was posted to our file sharing web site as mentioned before. I would like you to download it and pay attention to the code that we have discussed on Class 2. See that I have mapped a command to a function and inside this function the routing to create a line is performed. Go ahead, give a try! Compile this code and open the result ARX file inside AutoCAD.

Next class I will show how to build this application from scratch using the ARXWizard.
Stay tuned!

Saturday, February 05, 2005

Class 2 - AutoCAD's Database

Introduction

Each AutoCAD drawing represents a structured Database which stores several types of objects. When you just open a new drawing, AutoCAD creates behind the scenes a organized and efficient Database. This Database has a minimun data that allows you to make basic drawings.

This minimun data is represented basically by objects like layers, linetypes, text styles, etc. Due that you have layer 0, stadard text style, continuous linetype and others.
Since AutoCAD Release 2000 you can work with multiple drawings at the same time which is called MDI environment. This functionality brings great flexbility but also bring some extra complexity when dealing with more than one drawing. We won't discuss MDI aspects on this course but this will be probably a requirement for your future ObjectARX applications.

How data is stored

This Database mantains all sort of objects a drawing needs to exist. These objects are stored into appropriate containers which are special objects made to manage objects of the same type. This way we have appropriate methods and procedures to store entities, layers, text styles, etc.

Each object stored into Database receives an identifier that is called ObjectId. This identifier is unique inside the same AutoCAD session and it is valid during the lifecycle of each object. The ObjectId is generated by its Database and you don't need to worry about how to create it.

Inside ObjectARX we have basically 3 kind of objects:
  • Entities: Objects with graphical representation (lines, arcs, texts, ...);
  • Containers: Special objects to store and manage collections (layer table, linetype table, ...);
  • Objects: Objects without any graphical representation (groups, layouts, ...).



AutoCAD's Database structure

Creating objects

To create an object through ObjectARX we have some kind of recipe depending on what type of object it is and where we would like to store it (most of time we need to store an objects inside its specific container). Basically, you will follow this sequence:

  1. Declare a pointer to the object type you would like to create and call its new operator;
  2. With this pointer, call appropriate methods of this object to change its features;
  3. Get a pointer to the Database where you would like to create the object (most of time the current Database);
  4. Open the appropriate container where it should be stored;
  5. Call the specific container method to store your object passing its pointer;
  6. Receive its ObjectId automatically generated by its container;
  7. Finish the operation closing all opened objects including containers and the object you have just created.

Obviously you will create some handy classes to allow the automation of this processes because they are very similar and can be easily reused. The main idea is to create a sort of database utility funcions like: AddLayer, AddLine, AddCircle, AddTextStyle, etc.

* It is very important to not forget to close opened objects because this will cause AutoCAD to terminate.

Sample code to create a line (AcDbLine)

This code demonstrates how to create a simple line between two points. The process is simple and no error check is made. This code needs to be embedded inside an ObjectARX application structure to work. The main idea is to show you the concepts. Further we will create a working code. Pay attention to the order of opening and closing operations.



// We first need to declare a couple of points
AcGePoint3d startPt(1.0, 1.0, 0.0);
AcGePoint3d endPt(10.0, 10.0, 0.0);

// Now we need to instantiate an AcDbLine pointer
// In this case, its constructor allows me to pass the 2 points

AcDbLine *pLine = new AcDbLine(startPt, endPt);

// Now we need to open the appropriate container which is inside BlockTable
AcDbBlockTable *pBlockTable = NULL;

// First, get the current database and then get the BlockTable
AcDbDatabase* pDB = acdbHostApplicationServices()->workingDatabase();
pDB->getSymbolTable(pBlockTable, AcDb::kForRead);

// Inside BlockTable, open the ModelSpace
AcDbBlockTableRecord* pBlockTableRecord = NULL;
pBlockTable->getAt(ACDB_MODEL_SPACE, pBlockTableRecord, AcDb::kForWrite);

// After get ModelSpace we can close the BlockTable
pBlockTable->close();

// Using ModelSpace pointer we can add our brand new line
AcDbObjectId lineId = AcDbObjectId::kNull;
pBlockTableRecord->appendAcDbEntity(lineId, pLine);

// To finish the process we need to close ModelSpace and the entity
pBlockTableRecord->close();
pLine->close();



On the next class we will present the ObjectARX application structure and will build and compile a simple application using the above code. See you there!