Building a commercial grade lisp plugin installer in 5 easy steps

Rumors about the death of AutoLISP have been floating around for many years, but fear not, those rumors are greatly exaggerated. Bricscad and ZWCAD both have excellent support for lisp plugins, so well-written lisp code is truly cross-platform and enjoys a large and growing audience. Unlike other languages, the vast majority of lisp code works unmodified on any hardware architecture, in any version of Windows, and inside any host application that supports it, including AutoCAD versions released more than a decade ago. On top of that, OpenDCL gives lisp developers the power of a modern event-driven user interface that can put their lisp plugins on the same playing field as plugins written in any other language. This is a powerful combination, and given lisp’s low entry cost, it is not surprising to see lisp continuing to enjoy strong support in the developer community.

There’s just one thing missing: an easy way to install a lisp plugin on an end user’s computer. It’s a common refrain. How do you build a setup program for a lisp plugin? There are any number of free and low-cost installers available, but they are all designed for installing an executable program, not a plugin that must be configured to run inside a completely independent host application.

At one time there was a package called AcadInstall that was designed for AutoCAD add-ons, but that tool is long defunct. Autodesk has invented application bundles with the supposed benefit of making it easier to install and manage plugins, but these are not well documented and only work with recent versions of AutoCAD. For ManuSoft plugins, I use Visual Studio’s Setup and Deployment projects along with an extensive amount of custom C++ code to perform all the configuration necessary at install time. This works great for my needs, but it is well beyond the ability of most lisp developers.

After several recent online discussions with lisp developers struggling to get a working setup program, I set out to find a solution to this vexing problem. It turns out that after some initial work it’s actually not that hard to pull off a very professional looking setup program for a basic lisp plugin. In fact, if you follow these steps, in less than 10 minutes (5 minutes if you have a fast internet connection) you will have a working setup that installs a lisp plugin on any version of AutoCAD, Bricscad, or ZWCAD+. The best part: everything you need is free (as in beer)!

So, let’s get to it.

  1. Download and install Unicode Inno Setup QuickStart Pack from the Inno Setup Downloads page.
  2. Download my LispPluginSetup freebie and extract the files into a new folder somewhere.
  3. Download my LspLoad freebie and extract the files into a new subfolder named LspLoad.
  4. Double click on MyLispPlugin.iss. It should open in Inno Script Studio. Choose Project -> Compile.

At this point you should have a new Output subfolder with MyLispPluginSetup.exe inside. Go ahead, run it. After you’ve installed the MyPlugin sample, start the host application of your choice (the setup program configures all of them). If all went well, MyLispPlugin should display a command line message at startup alerting you to the fact that MYCOMMAND1 and MYCOMMAND2 are now available for use. Go ahead, try them. When you’re finished playing, it should uninstall cleanly (except for the new addition to TRUSTEDPATHS in AutoCAD 2014) when you choose Start -> MyCompany -> MyLispPlugin -> Uninstall My Lisp Plugin.

That was almost too easy, right? Well, not so fast. You’ll need to make some changes to adapt the sample for your own plugin. Take a look at the installation script in Inno Script Studio. Click on the Inno Setup Script item in the project tree to see the entire script as a flat file. Right near the top of the script, it should be obvious that you’ll need to change the basic plugin information preprocessor constants to adapt the script for your own plugin. Obviously your plugin will have a different base filename, and quite probably more files. It may have more registry keys and other basic setup stuff. In addition, you may not want to support all possible versions and flavors of each host app (in that case you’ll need to comment out or remove the associated item in the Files section). You get the idea, I’m sure.

Step 5 is modifying the sample script to adapt it for your own plugin. So easy, even an engineer could do it!

Registering an ARX/BRX module as a COM server

If you’re developing ARX modules that need to be registered as a COM server, you’re faced with some decisions about how to register them. In the old days before anyone cared about user permissions, registration could be safely accomplished at runtime, even via AutoLISP. Unfortunately runtime COM server registration just doesn’t work reliably any more under limited user accounts, not to mention registry redirection on 64-bit platforms. There is only one reliable way to register COM servers, and that’s doing it at install time under elevated privileges.

A normal Windows application might accomplish install-time registration by calling RegSvr32 after the files are copied to the destination folder, but this doesn’t work with ObjectARX or BRX modules. The reason it doesn’t work is because ARX modules cannot be loaded outside the AutoCAD or Bricscad process. RegSvr32 will fail with errors like “The module <filename> failed to load” or the even less helpful “The specified module could not be found.” There are some kludgy ways to get RegSvr32 to work anyway, but the simplest and most reliable way to solve this problem is to forget RegSvr32 and just add the needed registry values manually into your installer script. It’s not difficult, though it might be time consuming initially if your server implements a lot of COM objects.

At a minimum, a COM server must register at least one COM class under HKCRCLSID. If the COM server needs to support OLE Automation (e.g. VBA, AutoLISP) it must register a type library in HKCRTypeLib. In most cases, this is all that is needed, however you may also need to register a “ProgID” in HKCR if a script or in-process module needs to be able to connect to the server via human-readable ProgID.

Most installation script software can import Windows registry script (.reg) files, so it’s often helpful (and more maintainable) to create a registry script file manually, then simply import the .reg file into the installation script. If you use Visual Studio deployment projects, this is the only way to batch import registry values into the installation script. I’ve provided a minimal template for a registry script that registers a single COM object and ProgID. The template uses special characters as placeholders for the actual values: $$ is the human readable ProgID name, ## is the COM object’s CLSID, ** is the filename of your ARX module, and %% is the type library GUID. The type library and object class version numbers should match your actual version numbers as well, and of course [TARGETDIR] is the installation target directory that will be resolved at install time.

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT$$.1]
@=”$$ Class”

[HKEY_CLASSES_ROOT$$.1CLSID]
@=”{##}”

[HKEY_CLASSES_ROOTCLSID{##}]
@=”$$ Class”

[HKEY_CLASSES_ROOTCLSID{##}InprocServer32]
@=”[TARGETDIR]**.arx”
“ThreadingModel”=”Apartment”

[HKEY_CLASSES_ROOTCLSID{##}ProgID]
@=”$$.1″

[HKEY_CLASSES_ROOTCLSID{##}Programmable]

[HKEY_CLASSES_ROOTCLSID{##}TypeLib]
@=”{%%}”

[HKEY_CLASSES_ROOTCLSID{##}VersionIndependentProgID]
@=”$$”

[HKEY_CLASSES_ROOTTypeLib{%%}]

[HKEY_CLASSES_ROOTTypeLib{%%}1.0]
@=”$$ 1.0 Type Library”

[HKEY_CLASSES_ROOTTypeLib{%%}1.0]

[HKEY_CLASSES_ROOTTypeLib{%%}1.0win32]
@=”[TARGETDIR]**.arx”

[HKEY_CLASSES_ROOTTypeLib{%%}1.0FLAGS]
@=”0″

[HKEY_CLASSES_ROOTTypeLib{%%}1.0HELPDIR]
@=”[TARGETDIR]”

It’s really not that complicated for a single module. The work can be tedious to create all the values for multiple modules in scenarios where you support multiple AutoCAD and/or Bricscad versions or platforms, but these values typically don’t change over the life of the project, so it only needs to be done once. Once you have created the registry values manually, disable all other forms of COM server registration such as wizard-generated runtime registration or automatic “self-registration” at install time. A bonus side effect of the manual registration approach is that a normal uninstall reliably removes all traces of the COM server registration.

BRX on Linux: Getting Started

When I heard that Bricsys had shipped Bricscad for Linux, I was anxious to get to work on supporting the Linux platform. The first order of business was getting familiar with Linux. For that, I chose Ubuntu 10.10 32-bit running on a VMWare Workstation 7.1 virtual machine hosted on my Windows 7 64-bit workstation.

Installing Ubuntu was straightforward, and I had no problems. Installing Bricscad went off without a hitch. I downloaded the Debian package of Bricscad v11 Pro and Ubuntu’s Software Center installed it much like Windows Installer would install an MSI file on Windows.

Bricscad v11 on Ubuntu Application Menu

After installation, Bricscad fired right up. Except for a mysterious black splotch in the layer dropdown, it looked and felt very much like Bricscad on Windows.

Black Splotch on Bricscad Layer Dropdown

The next order of business was to build and load a BRX module. I started by installing Code::Blocks, an open source cross platform C/C++ IDE that can be used in both Windows and Linux. The IDE installed fine, but then things got interesting.

First of all, I found that I had to install the build tools (namely the g++ compiler), because they are not included with the IDE. Eventually I had to set an environment variable for my BRX project pointing it to the BRX SDK, which required a Code::Blocks plugin that had to be installed separately. I did get everything working, and built a simple BRX module without error — but then it refused to load in Bricscad.

Now, one of the things about Linux that is very different to Windows is the culture of users. Googling for help on something invariably leads to instructions that start out “It’s extremely easy to do this on Linux” and end with 4 pages of command line gibberish, including a list of all the stuff that must first be installed for these instructions to work correctly, and the inevitable warning that the instructions may only work on certain “distros” and versions of Linux.

I learned this first hand when I set out to determine why my .brx module was failing to load. I eventually learned that I had to manually add the BRX SDK library path to Bricscad so it could find the needed libraries at runtime. That was the easy part. To make a long (and rather harrowing) story short, I eventually determined that I was missing a single required library (the libgl graphics library). Installing the library in Ubuntu got things working.

Loading a test BRX module in Bricscad

Next up: figuring out how to build a Linux BRX module in Windows using the Visual Studio 2010 IDE. That should prove to be very interesting indeed.