.NET Command School, C# Edition
Making Your Custom Commands Look and Feel Like
AutoCAD®
Doug Goforth – National MultiTech LTD and CadPLUS Products
CP314-3 .NET Command School, C# Edition
About the Speaker:
As a 25 year drafting guru and long-time veteran at AU, Doug has participated in the CAD revolution since the days of
triangles and circle templates. He has led teams in converting and creating tens of millions of square feet of drawings
from numerous CAD platforms to AutoCAD®. He has created and implemented CAD and space standards and
procedures for major international companies working across sites and continents. He is consultant and programmer
for process and CAD managers at IBM, BellSouth, and many familiar engineering firms in the U.S. and abroad.
Having been trained in both fine art and computer programming gives Doug a creative outlook in the world of code
writers.
doug.goforth@nationalmultitech.com
CP314-3 .NET Command School, C# Edition
2
CP314-3 .NET Command School, C# Edition
Can the Average User Tell the Difference between Your Commands and
AutoCAD’s?
AutoCAD follows standard conventions when interacting with the user. Autodesk has many
years of observation and feedback that has helped in determining how to prompt for user
input. Novice and experienced users alike will expect to be presented with prompts and
dialogs in the conventions that they are accustomed to. You can gain a great advantage in
usability for your application by anticipating what the user will expect when prompted for
input while using AutoCAD.
Prompts and Dialog Parts You Should Emulate
Select objects:
Specify a point:
Specify first point:
Specify height :
Specify base point or [Displacement] :
Enter block name or [?]:
Enter an option [Next/Previous/Go/eXit] :
Anatomy of a Prompt
Prompts in AutoCAD follow a set format:
3
CP314-3 .NET Command School, C# Edition
.NET Managed Code Reference Requirements
1. acdbmdg.dll (ObjectDBX .NET Managed Wrapper)
2. acmgd.dll (AutoCAD .NET Managed Wrapper)
Autodesk Namespaces You Will Want to Include
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using DbTransMan = Autodesk.AutoCAD.DatabaseServices.TransactionManager;
using Autodesk.AutoCAD.Geometry;
Defining your Command with CommandMethod
CommandMethod is a member of Autodesk.AutoCAD.Runtime. It makes your command
available from the AutoCAD Command: prompt.
[CommandMethod("AUSCHOOL")]public void myAuschoolCommand() {
//Some lines of code
}
Writing to the Command: Line
Use the editor to write messages to the Command: line and to display prompts:
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
ed.WriteMessage(“Hello World!”);
Setting up Prompt Options
Getting the to
Use this combination to set up a prompt and get the results:
come at the end of the
Prompt Options + Prompt Results prompt
Prompt Options - Prompting for a point with keywords
Some objects have methods
PromptPointOptions prPtOpts = defined for DefaultValue:
new PromptPointOptions( PromptAngleOptions
"Please do something now “ + _
“[First thing/Second thing] :") PromptDistanceOptions
prPtOpts.Keywords.Add("First thing"); PromptDoubleOptions
prPtOpts.Keywords.Add("Second thing"); PromptIntegerOptions
prPtOpts.AllowNone = true; //Allow ENTER only
prPtOpts.AppendKeywordsToMessage = false; PromptStringOptions
Prompt Results - Prompting for a number with keywords These objects allow you to use
and default value AppendKeywordsToMessage
and DefaultValue to build the
PromptIntegerOptions prIntOpts = prompt in the correct order.
new PromptIntegerOptions( For all other objects you will
"Please type a number:");
prIntOpts.Keywords.Add("First thing"); have to build the entire prompt
prIntOpts.Keywords.Add("Second thing"); yourself if you plan to use
prIntOpts.AppendKeywordsToMessage = true; keywords with a default value.
prIntOpts.DefaultValue = 1;
4
CP314-3 .NET Command School, C# Edition
Displaying the Prompt
Use the Editor object to display the prompt. Each GETxxx method must be matched with its
corresponding Prompt Result Type. This will be displayed by VS2008’s intellisense feature.
static PromptPointResult prPtResult;
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
PromptPointOptions prPtOpts =
new PromptPointOptions("\nSelect point for AU Text:");
prPtResult = ed.GetPoint(prPtOpts);
Getting the User Response
Four ways the user can respond to a command line prompt:
1. Type something, text or a keyword
2. Select something
3. Press ENTER
4. Press ESCAPE
if (prPtResult.Status == PromptStatus.OK); //got expected response
else if (prPtResult.Status == PromptStatus.Keyword); //keyword entered
else if (prPtResult.Status == PromptStatus.None); //user pressed ENTER
else if (prPtResult.Status == PromptStatus.Cancel); //user cancelled
else
Be sure you have handled all of the possible outcomes for the prompt.
Entity Prompting and Responding
GetEntity will return an ObjectID (Try/Catch blocks have been omitted for clarity):
static PromptEntityResult prEntResult;
PromptEntityOptions prEntOpts = new PromptEntityOptions("Pick an object:");
prEntResult = ed.GetEntity(prEntOpts)
if (prEntResult.Status != PromptStatus.Error)
{
ObjectId entid = prEntResult.ObjectId;
Database db = HostApplicationServices.WorkingDatabase;
Autodesk.AutoCAD.DatabaseServices.TransactionManager tm =
db.TransactionManager;
using (Transaction myT = tm.StartTransaction())
{
Entity entity = (Entity)tm.GetObject(entid, OpenMode.ForRead, false);
ed.WriteMessage("You selected: " + entity.GetType().FullName);
myT.Commit();
}
}
5
CP314-3 .NET Command School, C# Edition
A Word about Using the Transaction Manager
The Transaction Manager provides a clean way to access the AutoCAD database and
manage the manipulation of AutoCAD objects in a drawing. The Transaction Manager
makes AutoCAD “aware” of your transaction, makes possible the “Undoing” of your
commands, and facilitates safe memory management.
Use the Transaction Manager in the following sequence:
1. Initialize the Transaction Manager
2. Use the TM to operate on the entity (query, create, modify)
3. Commit the Transaction
Using the Transaction Manager to get the selected object as an Entity type insures that a
proper object will be operated on without crashing the AutoCAD session.
Getting String Input from a Dialog
Use Modal dialogs to constrain user attention to the form:
Set form properties as shown below to eliminate confusion and erroneous navigation when
displayed. Modal dialogs should not be minimizable since this would prevent the user from
interacting with AutoCAD.
Also, set the DialogResult property of the OK button to DialogResult.OK
String strName = "";
frmName dlgName = new frmName();
dlgName.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
Application.ShowModalDialog(dlgName);
if (dlgName.DialogResult == System.Windows.Forms.DialogResult.OK)
{
strName = dlgName.TextBox1.Text;
}
dlgName.Dispose();
ed.WriteMessage("You entered " + strName);
A StartPosition of CenterParent will automatically center the form in the center of the AutoCAD
window.
6
CP314-3 .NET Command School, C# Edition
Getting Drawing Input from a Dialog
Use a Modal dialog for drawing selections. You must hide the form when interacting with
AutoCAD. You can use this.Hide and this.Show, but the editor provides the object
EditorUserInteraction for this purpose. Be aware that to use these you must include
references in your project to PresentationCore, PresentationFramework, and WindowsBase.
This dialog is designed to emulate the Pick Point feature on the Block Definition dialog in
AutoCAD.
7
CP314-3 .NET Command School, C# Edition
Making the Prompt Loop until User Exit
Always exit looping on ESC, an error, or expected end of recurring prompt (Try/Catch blocks
and Case Else have been omitted for clarity and space).
Question: Why is prPtOpts.Message redefined inside the loop?
_________________________________________________________
_________________________________________________________
8
CP314-3 .NET Command School, C# Edition
Launching by Prompt or Dialog
One AutoCAD convention you see a lot of is being able to launch a command with either a
prompt or a dialog depending on whether or not you use a dash in front of the command.
You can accomplish this by defining two commands in your application:
//Start command with a dialog
[CommandMethod("MYCOMMAND")] public void myCommandDialog()
-and-
//Start command with command line prompts
[CommandMethod("-MYCOMMAND")] public void myComand()
Each command method can be used to call common bits of code.
Making your Command Transparent (and other optional items)
Your command can be made transparent by specifying a command flag to the
CommandMethod function:
[CommandMethod("AUSCHOOL", CommandFlags.Transparent)]
public void myAuschoolCommand()
In addition to transparent commands, you can limit you application to SDI, only ModelSpace
and more.
9
CP314-3 .NET Command School, C# Edition
A Command to Load a Custom Toolbar (CUI file)
This example shows how to load a CUI file from a command. The file path must be
explicitly specified, or it must exist in the search path.
This command does double duty:
1. If the CUI file is not loaded, it loads the CUI file
2. If the toolbar is loaded, but turned off, it turns it on.
A Listing of Getxxx Methods for AutoCAD acgmd.dll
Use the Object Browser (F2) in Visual Studio to display a listing of Editor Members defined
in acmgd.dll.
10
CP314-3 .NET Command School, C# Edition
Defining LISP Functions
You can expose your command as a LISP function by using the LispFunction Class Attribute
when you define the function:
[LispFunction("AULISP")]
static public ResultBuffer auLispFunc(ResultBuffer myLispArgs)
{
Boolean success = false;
//Some lines of code
return success; //Returns t or nil
}
Parsing LISP function arguments
Arguments enter the function as a ResultBuffer object. You can easily enumerate the Typed
Values in the Result Buffer:
//Check for the correct number of arguments passed
if (myLispArgs.AsArray.Length != 1)
{
ed.WriteMessage("\nIncorrect number of arguments.");
return false;
}
foreach (TypedValue tVal in myLispArgs)
{
‘Operate or each argument
}
Taking arguments in order
Arguments are often expected with specific types and in a specific order. Assign the Result
Buffer to an array to retrieve the arguments in sequential order:
Array myArgs = myLispArgs.AsArray;
String fileName = (String)((TypedValue)myArgs[0]).Value;
Point3d myPoint1 = (Point3d)((TypedValue)myArgs[1]).Value;
Point3d myPoint2 = (Point3d)((TypedValue)myArgs[2]).Value;
Determining argument type
Arguments to a LISP function can be of varying types; string, double, integer, point, etc..
The type of argument passes is revealed in the TypeCode of the TypedValue. Use the
TypeOf operator to determine the value. Place the constant value of all the codes in your
class and then use a function to return the type:
if (typeof(tVal.Value) != String.GetType)
{
ed.WriteMessage("\n ; error: bad argument type:");
break;
}
else String fileName = tVal.value;
11
CP314-3 .NET Command School, C# Edition
Demandloading the application
When you demandload your application, you are making AutoCAD “aware” of the command.
This allows the dll to be loaded into AutoCAD without using the NETLOAD command.
This is accomplished by entering the proper registry keys for demandloading. Here is an
example (the line numbers are for convenience and should not be in the registry):
01 Windows Registry Editor Version 5.00
02 [HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD\R18.0\ACAD-8001:409\Applications\AUNetLoad]
03 "DESCRIPTION"="AU 2010 Demandload Example"
04 "LOADER"="C:\\Program Files\\AU2010\\ComSchool.dll"
05 "LOADCTRLS"=dword:00000002
06 "MANAGED"=dword:00000001
07 [HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD\R18.0\
ACAD-8001:409\Applications\AUNetLoad\Commands]
08 "AUNetLoad"="AUText"
09 [HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD\R18.0\
ACAD-8001:409\Applications\AUNetLoad\Groups]
10 "AUNetMan"="AUNetMan"
Line 02: The last item “AUNetLoad” is a unique name for your application.
Line 03: Any Description for the assembly.
Line 04: The actual location of the assembly.
Line 05: Double word value of loadreasons. Here is a table of possible loadreasons from
the AutoCAD Managed Class Reference:
LoadReasons
Name Value Description
Load the ObjectARX application when objects of custom classes it
kOnProxyDetection 0x01
controls are loaded via drawing open, dxfin, insert, and so on
kOnAutoCADStartup 0x02 Load the ObjectARX application when AutoCAD starts up
Load the ObjectARX application whenever an unknown command is executed
kOnCommandInvocation 0x04
for which it has a registry entry
Allow loading of the ObjectARX application via the
kOnLoadRequest 0x08
AcRxDynamicLinker::loadApp() method
kLoadDisabled 0x10 Do not demand load the ObjectARX application for any reason
kTransparentlyLoadable 0x20 Load the ObjectARX application transparently
We are using 0x02 in this example to load the application when AutoCAD starts. 0x0e is
also very common. It uses 0x01 + 0x02 + 0x04 + 0x08.
Line 06: A double word declaring that this is a managed .NET assembly.
This should always be 1.
Line 07: Specifies a subkey for defining commands.
Line 08: Specifies the command name in the class. String1 is the global command, String
2 is the local command. You can add as many commands as are in your assembly.
Lines 09 & 10: Specify the command group name in the module.
12
CP314-3 .NET Command School, C# Edition
AutoCAD 2010 English Product ID Registry Keys:
..\R18.0\ACAD-8001:409 = AutoCAD
..\R18.0\ACAD-8002:409 = Map
..\R18.0\ACAD-8003:409 = Mechanical Desktop for AIS
..\R18.0\ACAD-8004:409 = Architectural Desktop
..\R18.0\ACAD-8005:409 = AutoCAD Mechanical
..\R18.0\ACAD-8006:409 = Building Systems
..\R18.0\ACAD-8007:409 = AutoCAD Electrical
..\R18.0\ACAD-8008:409 = Land Desktop
..\R18.0\ACAD-8009:409 = AutoCAD LT
..\R18.0\AOEM-8001:409 = AutoCAD OEM
..\R18.0\ACAD-8013:409 = Mechanical Desktop for AIP
..\R18.0\ACAD-8022:409 = Autodesk Utility Design
..\R18.0\ACAD-8000:409 = Autodesk Civil 3D
..\R18.0\ACAD-8012:409 = Architectural Desktop w/Raster Design
The local id for English is 409. Other languages are indicated by other local id numbers. All
local ids for AutoCAD start with the number 4. English is 409, German is 407, and Chinese
is 404, and so on. You can find a complete list on Microsoft’s MSDN website at:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/nls_61df.asp
Here is an example of a completed registry entry in
HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD\R18.0\ACAD-8001:409\Applications\AUNetLoad\Commands
for demandloading the AUTEXT Command:
13
CP314-3 .NET Command School, C# Edition
Creating an install
There are many tools available for creating installation of your program. The three most
important things you will have to accomplish in your install are:
1. Installing the files
2. Setting the registry keys for demandloading the application
3. Providing a way to uninstall the application.
A very simple install to meet all three needs is available in Visual Studio. We will use the VS
Setup and Deployment module as an example.
Create the installation project
Create a new deployment project by selecting File>New>Project. Then select Setup Project.
Then modify the Project Properties:
Add the assembly dll to the deployment:
Visual Studio will automatically create the dependency files for the installation.
14
CP314-3 .NET Command School, C# Edition
Deploy Registry Keys
Right-click the project to add the tab for Registry entries:
Create the keys for the registry entries:
15
CP314-3 .NET Command School, C# Edition
Create a Launch Condition for the Deployment
You may want to create a launch condition for your deployment to insure that the required
registry tree exists and that AutoCAD is installed.
To create a Launch Condition:
Add a registry search:
Add the Launch Condition:
16