C++ Programming Guidelines

AutoCAD Land Desktop ActiveX & VBA

C++ Programming Guidelines

 

Importing Type Libraries

COM replaces the notion of header files with Type Libraries. In the Microsoft Visual C++ environment, you use the preprocessor directive #import in the StdAfx.h file to make all interfaces, properties, methods, events, enumerations, etc. available in your code. Use the no_namespace option to disable the requirement of qualifying each object with the type library name.

For example:

// create C++ wrapper classes for the COM interfaces

// new TLH and TLI files will be generated each time

#import "acax16enu.tlb" /*no_implementation*/ raw_interfaces_only no_namespace named_guids rename("GetObject", "acaxGetObject")

#import "AecXUIBase40.tlb" no_implementation raw_interfaces_only named_guids no_namespace

#import "AecXBase40.tlb" no_implementation raw_interfaces_only named_guids no_namespace

#import "LandAuto46.tlb" no_implementation raw_interfaces_only named_guids no_namespace

Note that the AecXBase type library references the AutoCAD AxDb16 type library. While you do not have to explicitly import AxDb16enu.tlb, it must be in the path or properly registered on your workstation, otherwise you will encounter errors when importing AecXBase40.tlb.

Initializing the COM libraries

When you create your project, you may safely omit the options "Automation" and "ActiveX Controls" to reduce the code size of your project. However, you will need to make 2 manual changes to ensure that the COM libraries are initialized:

In StdAfx.h:

#include <afxdisp.h> // MFC OLE automation classes

In your application’s InitInstance method:

// Initialize OLE libraries

if (!AfxOleInit())

{

  AfxMessageBox("OLE initialization failed.");

  return FALSE;

}

Connecting to the Land Desktop Application Object

In general, these are the steps to get to the running instance of the Land Desktop Application Object:

  • Call GetActiveObject to get the running instance of the AutoCAD application object. This method returns a pointer to IUnknown.

  • Call QueryInterface to get the interface IAcadApplication.

  • Call GetInterfaceObject to get the running instance of the Land Desktop application object. This method returns a pointer to IDispatch.

  • Call QueryInterface to get the interface IAeccApplication.

If you have several instances of AutoCAD applications running at the same time (AutoCAD, Land Desktop, Architectural Desktop, Raster Design), and you are developing an in-process application (e.g. ARX DLL), you can use these steps to get the correct instance of AutoCAD:

  • Call AfxGetApp to get a pointer to the CWinApp derived object.

  • Call GetIDispatch to get the IDispatch interface for the AutoCAD application object.

  • Call QueryInterface to get the interface IAcadApplication interface.

  • Call GetInterfaceObject to get the running instance of the Land Desktop application object. This method returns a pointer to IDispatch.

  • Call QueryInterface to get the interface IAeccApplication.

  • Call Init, passing in the IAcadApplication pointer to initialize the object model with the proper instance of AutoCAD.

When developing a stand alone (out of process) application that needs to handle multiple running instances of AutoCAD applications, you must enumerate the Running Object Table for the desired instance of AutoCAD in place of the call to AfxGetApp. See MSDN Article 190985 for details and sample code.

Restricted Properties and Methods

When you import a Type Library into your project, you may seem to have access to read-only properties and be able to invoke methods that are not documented in the AutoCAD Land Desktop ActiveX and VBA Reference. These "restricted" members of the interface are hidden in VBA and other macro languages, but are not filtered out by the import directive.

Be aware that these members cannot be called arbitrarily. Most are used for initializing the COM object, and will not update your project database. Refer to the AutoCAD Land Desktop ActiveX and VBA Reference for the list of supported interface members, or use the OLE Viewer supplied with the Microsoft Visual Studio Tools to determine which members are restricted.

Caching Interfaces

It is recommended that you cache the application object only (i.e. IAeccApplicationPtr). This will allow access to any object throughout the duration of your application.

For all other objects, it is generally safer to query for interfaces upon each use instead of caching and re-using pointers as class members or other non-local variables. This will avoid any confusion about the state of the interface object at the time of use.

Exception Handling

When you import a Type Library into your Microsoft Visual C++ project, the preprocessor generates both "raw" methods and "wrapper" methods in the *.tlh file. The raw methods return HRESULTs, which should be checked by the programmer. The wrapper methods hide the HRESULTs, providing error handling for you, and will issue a COM exception when an error occurs. While the wrapper methods provide a convenience to the developer, unhandled exceptions will appear in a dialog before your users.

In either case, you should handle these errors in your application. This can be accomplished in one of two ways:

  • Wrap all calls to wrapper methods in try-catch blocks

  • Check the HRESULT from the raw methods and implement error checking yourself

Smart Pointers

When you import a Type Library, the generated wrapper methods will use "smart pointers" whenever the method returns an interface. You must use a smart pointer in your code to ensure that the reference count on the object does not decrement to 0 before the call to the wrapper method returns. If you use a standard pointer, you will be left with the address of a released COM object, and an exception will occur when you try to use it.

COM Support classes

If an argument or return value of a wrapper class expects a _variant_t (or _bstr_t), do not use a VARIANT (or BSTR). This will compile, but will ultimately cause problems.

For example, the raw method for AeccCogoPoints.PointStringToArray looks like this:

virtual HRESULT __stdcall raw_PointStringToArray (BSTR PointString, VARIANT * Points ) = 0;

The wrapper method looks like this:

;_variant_t PointStringToArray (_bstr_t PointString );

The COM support class _variant_t automatically initializes its internal VARIANT using the correct constructor (the one that takes a VARIANT*, in this case). Note that while in general, the client is responsible for deallocating the memory allocated for the variant, the _variant_t (or _bstr_t) classes do it automatically for you.

MFC class Wizard Support

Through Microsoft's MFC classWizard, you can generate MFC classes from the Type Library. This gives you easy access to wrapped methods and properties. However, some of the Land Desktop objects are derived from AutoCAD or Aec objects. For example: AeccApplication, AeccDocument. When a MFC class is generated for these classes through classWizard, then only the additional methods and properties that Land Desktop added will be implemented in that new class. classWizard does not implement the methods and properties from the parent class.

ARX development

When registering a new command that will invoke ActiveX methods, use the ACRX_CMD_MODAL command flag. The command must be modal (and not transparent) so that no other commands or programs are currently active.

If you plan to use the Document.OpenProjectBased or Document.NewProjectBased methods in your registered command, be sure to add the ACRX_CMD_SESSION and ACRX_CMD_NOINTERNALLOCK flags. The former flag runs the command handler in the session fiber, while the later avoids locking the AutoCAD state out of quiescence (normally used with ActiveX calls). These flags are required to ensure that AutoCAD is in the proper context when switching documents.

Return values

In general, all properties and methods return S_OK when no errors are encountered. The return value E_FAIL is returned when an internal error condition prevents successful completion of the operation. An example is a memory allocation or other Win32 service failure. In certain cases, a return value of S_FALSE is returned to indicate that the operation did not complete due to user error. Some examples include trying to append an alignment entity that has no matching endpoint with the previous entity, or trying to access the coordinates of an elevation contour using an invalid elevation for the surface.

In your application, check for a return value of S_OK to indicate that no internal or user errors have occured.

Using "IntelliSense"

If you typically use IntelliSense to determine what properties and functions are available for a given interface, please be advised that restricted functions will show up in IntelliSense. These restricted functions are not supported, and in most cases will cause undesirable effects. The safe way to determine the supported functions is to consult the Help for AutoCAD Land Desktop ActiveX Objects.