Introduction

This page documents some ObjectARX programming tips and tricks that I've learned over the years. Most of the information presented here is the result of my own programming work, but some input comes from discussions on newsgroups or other forums. Contributors are listed at the end of each page, and their contributions are denoted with a superscripted number in brackets (e.g. [1]) in the area where they contributed information.

NOTICE: The contents of this page are Copyright 2004 - 2007 ManuSoft, All Rights Reserved. The contents of this page may not be reproduced under any circumstances without permission from the author! Permission to print one hardcopy of this page for individual use is hereby granted.

DISCLAIMER: ManuSoft is in no way responsible for either the accuracy or completeness of information on this page! Neither ManuSoft, Owen Wengerd, nor any credited or uncredited contributors may be held liable for any damages which may result either directly or indirectly from the use of information on this page! In other words, use at your own risk!

Owen Wengerd, President
ManuSoft

Microsoft Visual C/C++ Environment

To make it less confusing when working with multiple versions of ObjectARX, I recommend removing the ObjectARX SDK folders from your global VC settings, and adding them instead to the project settings for each individual project. Doing so gives you more local control over the project, and makes it less confusing when you need different build configurations to use different versions of ObjectARX in the same project.

I highly recommend setting up system environment variables to point to the locations of various versions of the ObjectARX SDK, as well as different versions of the MFC and C/C++ runtime libraries. This allows your build settings to specify the locations of include and library files using environment variables, thus making your projects much more portable across platforms and directory structures.

For example, I have every version of the ObjectARX SDK since ARX 1.0 installed on my system, and I have an environment variable pointing to the root of every SDK version, as follows:

Variable Value Description
ARX1 E:\SDK\ARX1 ARX 1.0 SDK (R13)
ARX2 E:\SDK\ARX202 ObjectARX 2.02 SDK (R14)
ARX2000 E:\SDK\ARX2000 ObjectARX 2000 SDK
ARX2000i E:\SDK\ARX2000i ObjectARX 2000i SDK
ARX2002 E:\SDK\ARX2002 ObjectARX 2002 SDK
ARX2004 E:\SDK\ARX2004 ObjectARX 2004 SDK
ARX2005 E:\SDK\ARX2005 ObjectARX 2005 SDK
ARX2006 E:\SDK\ARX2006 ObjectARX 2006 SDK
ARX2007 E:\SDK\ARX2007 ObjectARX 2007 SDK
ARX2008#32 E:\SDK\ARX2008.32 ObjectARX 2008 (x86) SDK
ARX2008#64 E:\SDK\ARX2008.64 ObjectARX 2008 (x64) SDK

The same thing should be done with other SDK code, including common tool libraries that are designed and maintained internally. In addition to the ObjectARX SDKs, I also have environment variables pointing to each version of Visual C/C++. Those are named MSVC2, MSVC4, MSVC42, MSVC5, MSVC6, MSVC7, MSVC71, and MSVC8, and each environment variable points to the root of the library (i.e. the VC98 folder for VC6, and the VC7 folder for VC7).

Once these environment variables are set up, you can refer to specific folders for specific SDKs in the VC6 and VC7 project settings by using the notation $(MSVC6)\Include (to point the VC6 C/C++ runtime include files) or $(MSVC42)\MFC\Lib (for VC4.2 MFC library files). The goal is to completely eliminate hardcoded paths from your project settings, thus making the projects portable. In addition to making the projects portable, this approach makes dependent SDKs portable as well. Moving an SDK to a different location or installing an updated SDK in a new location becomes as simple as changing an environment variable and rebuilding the project.

Assuming environment variables have been set to point to each version of VC, the following strings specify include and library paths for each version of VC:

Version Include Path
Library Path
VC 4.2 $(MSVC42)\Include;$(MSVC42)\MFC\Include
$(MSVC42)\Lib;$(MSVC42)\MFC\Lib
VC 6 $(MSVC6)\Include;$(MSVC6)\MFC\Include;$(MSVC6)\ATL\Include
$(MSVC6)\Lib;$(MSVC6)\MFC\Lib;$(MSVC6)\ATL\Lib
VC 7 $(MSVC7)\Include;$(MSVC7)\ATLMFC\Include
$(MSVC7)\Lib;$(MSVC7)\ATLMFC\Lib
VC 7.1 $(MSVC71)\Include;$(MSVC71)\ATLMFC\Include
$(MSVC71)\Lib;$(MSVC71)\ATLMFC\Lib
VC 8 $(MSVC8)\Include;$(MSVC8)\ATLMFC\Include
$(MSVC8)\Lib;$(MSVC8)\ATLMFC\Lib
VC 9 $(MSVC9)\Include;$(MSVC9)\ATLMFC\Include
$(MSVC9)\Lib;$(MSVC9)\ATLMFC\Lib

Using VC 7 (Visual Studio .NET 2002) to Build for AutoCAD 2000/2002

With the advent of AutoCAD 2004 and Visual Studio .NET, ObjectARX programmers are again faced with the task of moving from an older version of a compiler (VC6) to a newer version (VC7). Rather than maintain two versions of compilers and two versions of projects for supporting both AutoCAD 2000/2002 and the new AutoCAD 2004, it makes sense to use only the newest IDE to support *all* target AutoCAD platforms.

You can easily add build configurations in to your project VC7 so that the same project builds ObjectARX modules for both AutoCAD 2000/2002, and AutoCAD 2004, but the trick is to force VC7 to build your AutoCAD 2000/2002 target with the correct headers and libraries. In addition, you have to make sure your source code compiles correctly with both old and new ObjectARX SDK versions. This will likely require some conditional compilation if your code uses parts of the SDK that have been modified in ObjectARX 2004.

Following are some tips for successfully building ObjectARX 2000/2002 projects in VC7.

  • Don't put ObjectARX SDK folders into your global settings. Use the procedure outlined elsewhere on this page to define search paths in your project properties using environment variables.
  • Disable 'Edit and Continue' in all your AutoCAD 2000/2002 target builds. Go to project properties C/C++->General and set 'Debug Information Format' to anything except 'Program Database for Edit & Continue' (normally Debug builds should use 'Program Database' and Release builds should use 'Disabled'). Next, go to Linker->General and set 'Enable Incremental Linking' to 'No'. If you leave this option enabled, the linker pads the output file with uninitialized empty space, which causes the module validity checking in AutoCAD 2002 to choke on the file and fail to load it. Note that if you link to any libraries that were built with 'Program Database for Edit & Continue' enabled, the linker will warn that the /EDITANDCONTINUE switch was ignored. Just ignore the warning, or rebuild the offending library.
  • In your project properties, specify explicit paths for include files and library files to the correct version of ObjectARX and the VC6 version of the C/C++ runtime. Following is an example that shows the settings for include directories (if this project used MFC, it would also list $(MSVC6)\MFC\Include). You must do the same thing in settings under Linker->General for 'Additional Library Directories', except you must specify the library directory (e.g. $(ARX2000)\Lib and $(MSVC6)\Lib).
  • VC7 includes a new feature that inserts runtime buffer overrun checks into your Release builds by default. This runtime check uses a VC7 runtime library function that is not available in VC6, so you need to disable the feature when linking with VC6 libraries. To disable it, go to project properties and select the desired configurations, then navigate to settings for C/C++->Code Generation. Change the setting for 'Buffer Security Check' to 'No'*.
    Changing this setting prevents the following linker errors:

error LNK2019: unresolved external symbol ___security_cookie referenced in...
error LNK2019: unresolved external symbol @__security_check_cookie@4 referenced in...

* The current Microsoft Platform SDK now includes a separate library that provides implementations for these functions. Just link to bufferoverflowu.lib to resolve them correctly, with no need to turn off this new compiler feature (see KB894573).  

  • In VC6, casting a floating point number to a long caused the compiler to generate a call to a hidden library function named _ftol. VC7 generates a call to _ftol2 (obviously the implementation of this function changed, so the name was changed to prevent version clashes). If your source code includes a cast from double to long types, VC7 will generate a call to _ftol2, and the following linker error will result:

error LNK2001: unresolved external symbol __ftol2

Resolve this error by placing the following in one of your .cpp files (StdAfx.cpp, for example):

#if (_MSC_VER >= 1300) && (_MSC_VER < 1400) && (WINVER < 0x0500)
//VC7 or 7.1, building with pre-VC7 runtime libraries
extern "C" long _ftol( double ); //defined by VC6 C libs
extern "C" long _ftol2( double dblSource ) { return _ftol( dblSource ); }
#endif
  • If you use the /DELAYLOAD linker feature to delay-load implicitly linked DLLs, you will encounter the following linker errors when linking to VC6 libraries:

error LNK2001: unresolved external symbol ___delayLoadHelper2@8
error LNK2001: unresolved external symbol ___delayLoadHelper2@8

These errors are caused by a change in the delay load helper function in VC7, that was in turn the result of a change in the delay load import descriptor that the linker embeds inside the image file. Microsoft renamed the function to prevent the possibility of the new format produced by the VC7 linker being linked with the old helper function (that expects the old format). Unfortunately, AutoCAD's [brain dead] module validity testing chokes on the new delay load import descriptor format.

The solution to this problem is twofold: first make the linker happy by linking to the new VC7 delayimp.lib; second, postprocess the linker-created .arx module to hide the delay load import descriptor so AutoCAD can't choke on it.

  1. The first part of the solution involves renaming the VC6 delayimp.lib file* so VC7 doesn't find that one, and uses it's own version instead. The file is located in VC98\Lib. I renamed mine to VC6.delayimp.lib.
    * Arnold Eibel sent me an email with a better solution: instead of renaming the VC6 delayimp.lib, just specify an explicit path to the correct file to use. Arnold's suggestion is to use "$(VcInstallDir)lib\delayimp.lib", thus making the path portable to future versions of VC.
  2. The second part of the solution is not as difficult as it sounds. I made a command line utility to remove the delay load import directory from the file. This won't affect the file's operation at all, but it will prevent PE file viewers (such as Dependency Walker) from being aware of the delay loaded dependencies. Simply download the utility (165k) and place it somewhere in your VC7 support path (i.e. VC7\Bin) or better yet put it in its own folder and add the new folder to the path for executables in VC7 global options. Next, add a post build step to run the conversion utility on the target module. Do this in settings for Build Events->Post-Build Event, and add this to the 'Command Line' setting:
    HideDelayLoadImports.exe "$(TargetPath)"

These are the problems I have encountered so far in my conversion process. As I encounter new problems, I will add my solutions to this list of tips. If you have additions or comments, please don't hesitate to contact me via email (but please understand that sometimes I can't reply to every email I receive).


Using VC 7.1 (Visual Studio .NET 2003) to Build for AutoCAD 2000/2002/2004

Despite the minor numerical change from Visual C/C++ version 7 to 7.1, Microsoft made some major changes in the compiler and linker in order to become more C++ standard compliant. These changes make it virtually impossible to use 7.1 to build for ObjectARX 2004 and earlier ObjectARX versions. The new compiler chokes on the earlier versions of ATL and MFC libraries because they were not standard compliant, yet these are required when building for ObjectARX because of its reliance upon Autodesk libraries. What's more, the tricks outlined above are not enough to solve this problem.

The new features in the VC 7.1 IDE (not to mention the bug fixes) make it more desirable than VC 7. For that reason I wrote VC Build Hook, a small add-in for VC 7.1 that solves the compiler version problem by automatically switching the environment path to the VC 7 build tool directories at build time. This causes the build process to use the VC 7 build tools instead of the incompatible ones that shipped with VC 7.1. Note that you must have a working Visual C/C++ 7 (Visual Studio .NET 2002) installation in order for the path switching to work. If you only have Visual C/C++ 7.1 available, you must purchase the downgrade to Visual C/C++ 7 and install it also, otherwise the required VC 7 build tools won't be available on your system. This feature can be enabled for an entire solution or for individual projects.

See the following section for information about using the VC Build Hook utility.


Using VC Build Hook to Target Multiple AutoCAD Versions NEW

I created the VC Build Hook utility in order to make it possible to use the current Visual Studio IDE for building ObjectARX applications that target any version of AutoCAD. This is desirable because ObjectARX applications must be built by the Visual C/C++ build tools that correspond to the ObjectARX SDK version for the target AutoCAD version. VC Build Hook works by switching the executables path during a Visual Studio build and pointing the paths to the desired version of the Visual C/C++ build tools. In addition, VC Build Hook automatically fixes build tool command options to account for differences between VC versions so that build commands produced by one version of Visual Studio are correctly interpreted by another version of the build tools. Assuming you've already set up your projects as described above (note that you must have a working installation of the necessary version of Visual C/C++ build tools and runtime libraries), then you'll need to install the current version of VC Build Hook:

Download: VCBuildHookSetup.msi (278k)
Version 3.0.0.2 uploaded 2007-12-02 (supports VC 7.1, VC 8, and VC 9)

Once the VC Build Hook utility is installed, it's just a matter of making some changes in your project settings to ensure that your build succeeds. First, you must ensure that the correct headers and libraries are included in your project settings as outlined above. Second, you must set the VC Build Hook extended properties for your projects to use the correct build tools.

When VC Build Hook is started, Visual Studio solutions will have two new extended properties: LowPriorityBuild and BuildToolVersion.

The LowPriorityBuild property is only available for solutions and can be either 'Yes', 'No', or 'NotSet'. Currently, VC Build Hook makes all builds low priority unless this property is set to 'No'. A low priority build means that other tasks will receive more processor time during a build (at the expense of build time, of course). The BuildToolVersion property is available for solutions or projects, and may be set to 'VC7', 'VC8', or 'Default'. A setting of 'Default' for projects causes the solution property to be inherited. If the project and solution are both set to 'Default', then the build tool paths will not be affected and Visual Studio will use the default build tools.

When using Visual Studio 2005 or later IDE:

  • Disable parallel builds! The VC Build Hook utility does not work correctly if two simultaneous builds are using different settings, so you should disable this feature in Visual Studio global options. To do this, go to Tools->Options, open 'Projects and Solutions', select the 'Build and Run' tab, and change the 'maximum number of parallel project builds' to 1. In my experience, Visual Studio is more stable when parallel builds are disabled, so there is a benefit to disabling this feature that is unrelated to VC Build Hook.

When using the VC 7 build tools:

  • Disable the Manifest Tool. This is easy to do, but not obvious or well documented. Right-click on a project and select 'Tool Build Order...', then select 'All Configurations' in the configuration dropdown and dismiss the warning dialog, then uncheck the box beside 'Manifest Tool'. Using the IDE, you have to do this one project at a time.
  • In linker settings, on the 'Manifest File' tab, set 'Generate Manifest' to 'No'. This disables manifest file generation.
  • Disable error reporting. In C/C++ settings, on the 'Advanced' tab, set 'Error Reporting' to 'Default'. Do the same in linker settings, on the 'Advanced' tab.
  • Don't use Unicode response files. Change this in C/C++ settings on the 'General' tab by setting 'Use UNICODE Response Files' to 'No'. Do the same in linker settings, also on the 'General' tab. The VC Build Hook utility will automatically convert Unicode response files to ANSI files if they are being sent to a VC 7 build tool, so this step is not strictly required, however the build will be slightly less efficient if the files need to be converted.
  • If your project uses precompiled headers, there is one additional issue to deal with. Visual Studio 2005 removed support for the "Automatically Generate" (/YX) precompiled header option. This is not a problem when using the VC 8 or later build tools, but when using the VC 7 build tools, it can make the build process unbearably slow. Luckily it's not difficult to re-enable automatic use of precompiled headers when building with VC 7 build tools. To re-enable this feature in a project that is using the VC 7 build tools, you need to edit the 'Precompiled Header' tab of the C/C++ settings. First, make sure precompiled headers are disabled ('Create/Use Precompiled Header' should be set to 'Not Using Precompiled Headers'), then set the 'Precompiled Header File' to '$(IntDir)\$(TargetName).pch' for all configurations, then go to the 'Command Line' tab and add '/YXStdAfx.h' to the 'Additional options' field at the bottom. Voila! Precompiled headers should now work just as they did when building with the Visual Studio .NET 2003 IDE.

I need to stress again that these steps only work without error after you have implemented the practices I've discussed in the previous sections.


Enabling IntelliSense and Class Browsing for ObjectARX Headers

A common complaint among ObjectARX programmers is that Visual C/C++ doesn't display IntelliSense context menus for classes defined in the ObjectARX headers. The trick is to include all the ObjectARX headers files somewhere in your solution. I created a new folder called ARXHeaders with subdirectories for every version of the ObjectARX SDK:

ARXHeaders
   ARX2
   ARX202
   ARX2000
   ARX2000i
   ARX2002
   ARX2004
   ARX2005
   ARX2006
   ARX2007
   ARX2008

In each subdirectory, create a new empty static library project named e.g. 'ARX2007' and add every header file (*.h) from that version of the ObjectARX SDK to the project. It's important to give each project a unique name so that the project names don't collide when more than one is added to a single solution. Since there are no source files, there is no output file for these projects, and building them is a no-op. Nevertheless, adding one of these projects to an existing solution causes VC to "see" the ObjectARX classes and code definitions for use in IntelliSense. Another benefit of including the ObjectARX headers in the solution is the ability to use the class browser in VC to browse the ObjectARX SDK. Browsing can reveal some interesting undocumented functions, and it also proves very useful for providing a readable overview of class hierarchies and object definitions.

In projects that target multiple versions of AutoCAD (and therefore use multiple versions of the ObjectARX SDK) you can add the ARXHeaders project for each target version of ObjectARX. While adding multiple SDK versions won't tell VC which version of the SDK is used in a given source file or project, it does make each version separately available in the VC class browser for easy browsing.


Demand Loading a VLX File

The registry demand loading feature in AutoCAD is a great method for loading ObjectARX modules when AutoCAD starts, and it's relatively easy to create the demand loading settings from an installation program or MSI file at install time. Unfortunately it only works for .arx files (and also with .NET dlls since AutoCAD 2006). Some years ago, I created a small ObjectARX module called LoadVLX. The purpose of this module was to work as a stub to load an associated .vlx file of the same base name in the same folder. The idea is to rename the VLXLoad.arx to the name of the associated .vlx file (i.e. MyApp.arx will look for and load MyApp.vlx in the same directory), then create demand load registry settings to load the renamed .arx file. Voila, the associated .vlx file gets loaded as if it was being demand loaded from the registry.

The VLXLoad source code demonstrates an important technique that I often see questions about in Autodesk's ObjectARX discussion group: how to get the full path to the .arx file from code within the file. The secret is to use the Windows API function GetModuleFileName(), passing as its first argument the current module instance handle, which is available in an ObjectARX module as _hdllInstance (note that it's _h, two lower case L's, then followed by an upper case I for Instance).

To make things easy, I've uploaded here the complete source code along with solution files for both Visual Studio 2002 (AutoCAD 2000 - 2006) and Visual Studio 2005 (AutoCAD 2007 - 2008). These solutions should build with no changes so long as you've defined environment variables as described elsewhere on this page. The modules for each target AutoCAD version are built with the same name, so be careful not to get them confused. If you look at the source code, you'll notice that they also define a lisp callable function named (GetPathOf<basefilename>) that returns the directory from where the .arx module loaded. This also demonstrates another technique: defining an ADS (Lisp callable) function by "calculating" the function name at runtime.

Download: VLXLoadSource.zip (87k)
Version 1.0.0.1 uploaded 2006-12-04

If you just want the .arx modules, download the latest versions from my Freebies page. Note that the original binaries on the Freebies page do not contain file version information, and they are built completely in Visual Studio 2005 with the help of my VCBuildHook utility.


Contributors

<None>

 
AutoCAD is a registered trademark of Autodesk, Inc.  
    Copyright 2007 ManuSoft