v3 CP4177 Ambrosius

You might also like

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 30

Leveraging ActiveX Libraries with AutoLISP

Lee Ambrosius Autodesk, Inc.

CP417-7

Do you have the basics of AutoLISP mastered and want to evolve from Newbie to Master? This class might be just what you are looking for. You will learn how to work with events and reactors, access the Windows Registry, use AutoCAD and Windows ActiveX libraries, and connect to other Windows applications, such as Microsoft Word or Excel. This class is not recommended for those new to AutoLISP.

Learning Objectives
At the end of this class, you will be able to: Use the AutoCAD ActiveX library to access objects in an open and closed drawing Access and store values in the Windows Registry, Xdata, Xrecords, and Dictionaries Define application, document, and other types of reactors Manipulate the Windows environment Use AutoCAD to drive Microsoft Office applications, such as Microsoft Word and Excel

About the Speaker


Lee is one of the technical writers on the AutoCAD team at Autodesk and has been an AutoCAD user for over 15 years in the fields of architecture and facilities management. He has been teaching AutoCAD users for over a decade at both the corporate and college level. He is best known for his expertise in programming and customizing AutoCAD-based products, and has 10+ years of experience programming with AutoLISP, VBA, Microsoft .NET, and ObjectARX. Lee has written articles for AUGI publications and white papers for Autodesk on customization. He is the author of several books on AutoCAD and has been an active technical editor for AutoCAD books in the Bible and For Dummies series. Twitter: http://twitter.com/leeambrosius Email: lee.ambrosius@autodesk.com Blog: http://hyperpics.blogs.com

CP417-7: Leveraging ActiveX Libraries with AutoLISP

Contents
1 2 3 4 5 6 Use the COM Library with Open and Closed Drawings ....................................................... 3 Accessing and Storing Information for Use Later ................................................................ 5 Monitoring Activity in AutoCAD with Reactors ....................................................................15 Working with Windows .......................................................................................................17 Working with Microsoft Office .............................................................................................21 Where to Get More Information ..........................................................................................30

CP417-7: Leveraging ActiveX Libraries with AutoLISP

Use the COM Library with Open and Closed Drawings

AutoCAD 2000 marked a major expansion of the AutoLISP development language which added hundreds of new functions, and most of these functions allowed you to access objects in a drawing like never before. This expansion of the AutoLISP language is known as Visual LISP and it allows you to use the COM libraries that come with AutoCAD and other applications that support a COM interface. Using the COM interface, you can access objects in AutoCAD in a much different way than you might have in the past through using AutoCAD commands or DXF code values. Below are some basic examples of how to work with the COM (Component Object Model) library in the current drawing and a drawing that is not even open in the current session of AutoCAD. The COM interface allows you to access the AutoCAD application or a document object. Once you have an object, you can list the available properties and methods for the object by using the vlax-dump-object function with the T flag. The syntax for the vlax-dumpobject function is (vlax-dump-object obj [flag]). For example, (vlax-dump-object (vlax-get-acad-object)) displays the properties and methods available for the AutoCAD application object. Tip: When using the Visual LISP functions, you must use the (vl-load-com) function in order to access the methods and properties in the AutoCAD COM library.

Create Objects Using the COM Interface


;; Create a blue circle using Visual LISP (defun c:CreateCircle-VL ( / acadObj docObj spaceObj cenPoint circObj) (setq acadObj (vlax-get-acad-object)) (setq docObj (vla-get-activedocument acadObj)) (if (= (vla-get-activespace docObj) acModelSpace) (setq spaceObj (vla-get-modelspace docObj)) (setq spaceObj (vla-get-paperspace docObj)) ) (setq cenPoint (vlax-make-safearray vlax-vbdouble '(0 . 2))) (vlax-safearray-fill cenPoint '(5.0 5.0 0.0)) (setq circObj (vla-addcircle spaceObj cenPoint 1.75)) (vla-put-color circObj 5) (princ) )

Modifying Objects Using the COM Interface


;; Change all objects to ByLayer (defun c:ChangeAll2ByLayer ( / acadObj docObj spaceObj for-item) (setq acadObj (vlax-get-acad-object))

CP417-7: Leveraging ActiveX Libraries with AutoLISP

(setq docObj (vla-get-activedocument acadObj)) (if (= (vla-get-activespace docObj) acModelSpace) (setq spaceObj (vla-get-modelspace docObj)) (setq spaceObj (vla-get-paperspace docObj)) ) (vlax-for for-item spaceObj (vla-put-color for-item acByLayer) (vla-put-linetype for-item "BYLAYER") (vla-put-lineweight for-item acLnWtByLayer) ) (princ) )

Opening Drawings with ObjectDBX


ObjectDBX allows you to work with drawings much more efficiently when you need to quickly manipulate or access the contents of a drawing without opening the drawing in the application. When a drawing is opened using ObjectDBX, you are limited to accessing the objects differently than you do the document window. The biggest limitation that you are bound to when working with ObjectDBX is not being able to get input from the user through object selections and points in the drawing. The following sample code uses ObjectDBX to open a drawing in memory and copy all of the dimension styles from the in memory drawing into the current drawing.
;; Open drawing in the background and import all dimension styles (defun c:AccessExternalDrawing ( / acdbObj cntDimstyles acObject arTemp arDimStyles cntStep) (if (= acLibImport nil) (progn (vlax-import-type-library :tlb-filename "C:\\Program Files\\Common Files\\Autodesk Shared\\axdb18enu.tlb" :methods-prefix "acdbm-" :properties-prefix "acdbp-" :constants-prefix "acdbc-" ) (setq acLibImport T) ) ) (setq acdbObj (vlax-create-object "ObjectDBX.AxDbDocument.18")) (acdbm-open acdbObj "c:\\datasets\\CP417-7\\data files\\External Drawing.dwg") (setq cntDimstyles 0)

CP417-7: Leveraging ActiveX Libraries with AutoLISP

(vlax-for acObject (vla-get-Dimstyles acdbObj) (setq arTemp arDimStyles) (setq arDimStyles (vlax-make-safearray vlax-vbObject (cons 0 cntDimstyles))) (setq cntStep 0) (repeat cntDimstyles (vlax-safearray-put-element arDimStyles cntStep (vlax-safearray-get-element arTemp cntStep)) (setq cntStep (1+ cntStep)) ) (vlax-safearray-put-element arDimStyles cntDimstyles acObject) (setq cntDimstyles (1+ cntDimstyles)) ) (setq acadObj (vlax-get-acad-object)) (setq docObj (vla-get-activedocument acadObj)) (setq dbObj (vla-get-database docObj)) (setq dimstylesColl (vla-get-dimstyles dbObj)) (vla-copyobjects acdbObj arDimStyles dimstylesColl) (vlax-release-object acdbObj) (princ) )

Accessing and Storing Information for Use Later

The commands that you use in AutoCAD often store previously used values so you can quickly access these values the next time you use the command in the same drawing session, between drawing sessions, or globally across all drawings and sessions. The way information is stored for use later by a command depends on what the command is used for. The following are several different examples of how AutoCAD stores values for different commands: CIRCLE command The last radius entered is maintained within only the current drawing session, and once the drawing is closed the setting is lost. FILLET command The last fillet radius entered is maintained between sessions, so if the drawing is closed and re-opened the last value entered is the one that is used by the FILLET command the next time it is started. OPTIONS command The last profile set current is the profile that is used for each drawing that is opened and when AutoCAD is closed and re-opened. 5

CP417-7: Leveraging ActiveX Libraries with AutoLISP

When creating custom applications, often persisting information is just done within the current drawing and session, so if the drawing is closed the routine usually uses a set of default values the next time it is loaded. This might be ideal for many custom routines, just like the CIRCLE command but might not be the best user experience. Visual LISP allows you to access the Windows Registry to persist data across multiple sessions of AutoCAD at a time. The Windows Registry can be great for storing the paths of custom blocks or even a setting used to determine which discipline should be used for a set of custom tools that are designed to work differently for each discipline. If you want to store different information on a per drawing basis, you can create custom dictionaries. Xrecords are then appended to a dictionary and contain the information that you want to persist similar to system variables, but you can post multiple values to a single record. Xdata can also be used to attach custom information per object in a drawing. Important: When working with the Windows Registry, exercise caution as you do not want to overwrite or delete a key that you did not create or do not understand what its intended purpose is. If you start altering values and keys for an application other than your own, the application may become unstable the next time it is used. The Windows Registry can be modified and viewed using the Registry Editor which can be started using Run from the Start menu and typing regedit.exe.

Windows Registry
Visual LISP offers four main functions that are used to read and write values to and from the Windows Registry. The functions that are available for working with the Windows Registry are listed in the following table. Function with syntax vl-registry-delete (vl-registry-delete key [value]) vl-registry-descendents (vl-registry-descendents key [value(s)]) vl-registry-read (vl-registry-read key [value]) vl-registry-write (vl-registry-write key [value data]) Writes a single piece of data from to the default value of a key or a specific value Reads the data from the default value of a key or a specific value Returns a listing of either subkeys or value names of the key specified Description Removes a key or value from the registry

CP417-7: Leveraging ActiveX Libraries with AutoLISP

;; Command demonstrates the use of the functions ;; used to work with the Windows Registry. (defun c:WinReg ( / reg-val) (alert (strcat "Current Discipline: " (if (setq reg-val (vl-registry-read "HKEY_CURRENT_USER\\Software\\ABC" "Discipline")) reg-val "<Missing>") ) ) (vl-registry-write "HKEY_CURRENT_USER\\Software\\ABC" "Discipline" "Civil") (vl-registry-write "HKEY_CURRENT_USER\\Software\\ABC" "RelativeBlockPath" "/Custom/Blocks") (vl-registry-write "HKEY_CURRENT_USER\\Software\\ABC\\MyDraftingSettings" "FilletRadius" 0) (vl-registry-write "HKEY_CURRENT_USER\\Software\\ABC\\MyLayerSettings" "NotesLayer" "Notes") (vl-registry-descendents "HKEY_CURRENT_USER\\Software\\ABC") (startapp "regedit") (princ) )

Xdata, Dictionaries, and Xrecords


Storing data in the Windows Registry is nice, but is not always a practical approach if the data changes from drawing to drawing or even object to object. AutoCAD allows you to store information on individual objects as well as in custom dictionaries. Each object in the drawing can have non-graphical data associated with it; this data is stored as Xdata. Custom dictionaries can be created and used to store data in what are called Xrecords which are similar in concept to a row in a spreadsheet or database. Diagram of how Xdata is stored Drawing Model Space Object Xdata Diagram of how a global Dictionary is stored Drawing Dictionaries Collection Dictionary Xrecord1 Xrecord2 7

CP417-7: Leveraging ActiveX Libraries with AutoLISP

Diagram of how a Dictionary is stored on a per object as an extension dictionary Drawing Model or Paper Space Object Dictionary Xrecord1 Xrecord2 When assigning Xdata to an object you use the DXF codes that are 1000 and higher. Based on the value that you want to store in the Xdata, you must use the corresponding DXF code value. The following table lists the DXF codes and the value types that can be used with them. DXF Code 1000-1009 1010-1059 1060-1070 1071 Value Type String (255 character limit prior to AutoCAD 2000 or 2049 single Double 16 32

Before you assign Xdata to an object, you must first register the name of the application associated with the Xdata using the Regapp function. The Regapp function takes a single argument and that is the application name, (regapp app). There are several different ways of working with Xdata, dictionaries, and Xrecords and the method that you choose is based on whether you are more comfortable with Classic AutoLISP or Visual LISP functions. The following table lists the functions that are part of Visual LISP for working with Xdata. Utilizing Classic AutoLISP allows for your programs to work on Windows and Mac OS X. Function with syntax vl-get-xdata (vl-get-xdata obj app artypes arvalues) vl-set-xdata (vl-set-xdata obj artypes arvalues)
;; Demonstrates how to attach Xdata using the xdataLISP-VL helper function (defun c:SetXdata-VL ( / xDtype xDvalue) (setq xDtype (vlax-make-safearray vlax-vbinteger '(0 . 5))) (setq xDvalue (vlax-make-safearray vlax-vbvariant '(0 . 5))) (vlax-safearray-fill xDtype (list 1001 1000 1002 1070 1005 1002))

Description Retrieves the data for an application on an object Sets or removes the data for an application on an object

CP417-7: Leveraging ActiveX Libraries with AutoLISP

(vlax-safearray-fill xDvalue (list "ACAD" "DSTYLE" "{" 347 (cdr (assoc 5 (entget (tblobjname "ltype" "center")))) "}")) (xdataLISP-VL (car (entsel "\nSelect object to add Xdata to: ")) "ACAD" xDtype xDvalue ) ) ;; Removes the attached Xdata using the xdataLISP-VL helper function (defun c:RemoveXdata-VL () (setq xDtype (vlax-make-safearray vlax-vbinteger '(0 . 0))) (setq xDvalue (vlax-make-safearray vlax-vbvariant '(0 . 0))) (vlax-safearray-fill xDtype (list 1001)) (vlax-safearray-fill xDvalue (list "ACAD")) (xdataLISP-VL (car (entsel "\nSelect object to remove Xdata from: ")) "ACAD" xDtype xDvalue) ) ;; Helper function for SetXdata-VL and RemoveXdata-VL ;; Example (xdataLISP-VL entityName "MyApp" xDataTypeCodes xDataValues) (defun xdataLISP-VL (entityName appName xDtypeNew xDvalueNew / obj dimSize dimSizeNew xDtypeOld xDvalueOld) (if (/= entityName nil) (progn (regapp appName) (setq obj (vlax-ename->vla-object entityName)) (vla-getxdata obj appName 'xDtype 'xDvalue) (vla-setxdata obj xDtypeNew xDvalueNew) ) ) (princ) )

The Visual LISP approach to working with Xdata can be more complex when compared to Classic AutoLISP, but it is easier to use once you understand the syntax and structure of creating and assigning Xdata. The following table lists the functions that you will use when working with Xdata in Classic AutoLISP. You will also still need to use the Regapp function as previously described.

CP417-7: Leveraging ActiveX Libraries with AutoLISP

Function with syntax entget (enget ssname) assoc (assoc dxf-code entdata) cons (assoc dxf-code value) subst (subst new-list old-list org-list)

Description Retrieves the data for an entity

Searches out an element in a list and returns only the associated list Constructs a dotted pair, DXF code type and value Substitutes an old list of values for a new list

;; Demonstrates how to attach Xdata using the xdataLISP helper function (defun c:SetXdata () (xdataLISP (car (entsel "\nSelect object to add Xdata to: ")) (list "ACAD" '(1000 . "DSTYLE") '(1002 . "{") '(1070 . 347) (cons 1005 (cdr (assoc 5 (entget (tblobjname "ltype" "center"))))) '(1002 . "}")) ) ) ;; List the Xdata attached to an object (defun c:ListXdata () (assoc -3 (entget (car (entsel "\nSelect object to lists Xdata: ")) '("*"))) ) ;; Removes the attached Xdata using the xdataLISP helper function (defun c:RemoveXdata() (xdataLISP (car (entsel "\nSelect object to remove Xdata from: ")) '("ACAD")) ) ;; Helper function for SetXdata and RemoveXdata ;; Example (xdataLISP entityName '("MyApp" (1004 . "Piping")))) (defun xdataLISP (entityName lstValue / entData) (if (/= entityName nil) (progn (regapp "ACAD") (setq entData (entget entityName '("ACAD"))) (if (/= (assoc -3 entData) nil) (if (= (nth 0 (cadr (assoc -3 entData))) "ACAD")

10

CP417-7: Leveraging ActiveX Libraries with AutoLISP

(setq entData (subst (cons -3 (list lstValue)) (assoc -3 entData) entData)) (setq entData (append entData (list (list -3 lstValue)))) ) (setq entData (append entData (list (list -3 lstValue)))) ) (entmod entData) (entupd entityName) ) ) (princ) )

Like Xdata, dictionaries are used to hold non-graphical data that can be referenced by multiple different objects in a drawing at a time. Multiline styles, groups, and layer filters among others are stored in named dictionaries. Dictionaries can hold objects and Xrecords, commonly Xrecords are stored in a dictionary but that depends on what the dictionary is used for. When assigning values to an Xrecord, you use DXF codes just like you do for defining Xdata but the DXF codes used fall into the normal range used for objects which is between 1 and 369. The following table lists the DXF codes used with Xrecords and the value types that they can be assigned. For additional information on DXF codes look up the topic Group Codes in Numerical Order in the AutoCAD online help system. DXF Code 0-9 Value Type String (255 character limit prior to AutoCAD 2000 or 2049 single-byte characters with AutoCAD 2000 or later) Double precision 3D point value Double-precision floating-point value 16-bit integer values 32-bit integer values String (255-character maximum string lengths) String (255-character maximum string lengths) String representing hexadecimal value (handle) Double precision floating-point value Double precision floating-point value Double precision floating-point value Double precision scalar floating-point value 16-bit integer value 11

10-39 40-59 60-79 90-99 100 102 105 110-119 120-129 130-139 140-149 170-179

CP417-7: Leveraging ActiveX Libraries with AutoLISP

210-239 270-279 280-289 290-299 300-309 310-319 320-329 330-369

Double-precision floating-point value 16-bit integer value 16-bit integer value Boolean flag value Arbitrary text string String representing hex value of binary chunk String representing hex handle value String representing hex object IDs

Since dictionaries are stored in the drawing differently than Xdata and contain Xrecords, you must use a different set of functions from those that you have already seen with Xdata. The following table lists the Visual LISP functions used to work with Xrecords and dictionaries. Function with syntax vla-get-dictionaries (vla-get-dictionaries document) vla-addxrecord (vla-addxrecord dict-obj name) vla-setxrecorddata (vla-setxrecorddata xrec-obj types values) vla-getxrecorddata (vla-getxrecorddata xrec-obj types values)
;; Create a dictionary using Visual LISP (defun c:CreateDictionary-VL ( / ); acadObj docObj dictsColl) (setq acadObj (vlax-get-acad-object)) (setq docObj (vla-get-activedocument acadObj)) (setq dictsColl (vla-get-dictionaries docObj)) (setq dictObj (vla-add dictsColl "MY_CUSTOM_DICT2")) (setq xrecObj (vla-addxrecord dictObj "XREC_1")) (setq xDtype (vlax-make-safearray vlax-vbinteger '(0 . 2))) (setq xDvalue (vlax-make-safearray vlax-vbvariant '(0 . 2))) (setq xPoint (vlax-make-safearray vlax-vbdouble '(0 . 2))) (vlax-safearray-fill xPoint '(5.0 5.0 0.0))

Description Retrieves a listing of all the dictionaries stored in the drawing Adds an Xrecord to the dictionary object Sets the data on an Xrecord

Gets the data on an Xrecord

12

CP417-7: Leveraging ActiveX Libraries with AutoLISP

(vlax-safearray-fill xDtype '(1 10 71)) (vlax-safearray-fill xDvalue (list "Visual LISP Dictionary" xPoint 11)) (vla-setxrecorddata xrecObj xDtype xDvalue) (princ) ) ;; Delete a dictionary using Visual LISP (defun c:DeleteDictionary-VL ( / acadObj docObj dictsColl dictObj) (setq acadObj (vlax-get-acad-object)) (setq docObj (vla-get-activedocument acadObj)) (setq dictsColl (vla-get-dictionaries docObj)) (vla-delete (vla-item dictsColl "MY_CUSTOM_DICT2")) (princ) ) ;; Prints the data from an Xrecord using Visual LISP (defun c:PrintXrec-VL ( / acadObj docObj dictsColl dictObj xrecObj xDtype xDvalue) (setq acadObj (vlax-get-acad-object)) (setq docObj (vla-get-activedocument acadObj)) (setq dictsColl (vla-get-dictionaries docObj)) (setq dictObj (vla-item dictsColl "MY_CUSTOM_DICT2")) (setq xrecObj (vla-item dictObj "XREC_1")) (vla-getxrecorddata xrecObj 'xDtype 'xDvalue) (if (/= xDtype nil) (progn (princ (vlax-safearray->list xDtype)) (terpri) (princ (vlax-safearray->list xDvalue)) ) ) (princ) )

13

CP417-7: Leveraging ActiveX Libraries with AutoLISP

The following table lists the functions that you can use to work with dictionaries in Classic AutoLISP. Function with syntax dictadd (dictadd dict-entity rec-name entity) dictremove (dictremove entity name) dictnext (dictnext entity [flag]) dictrename (dictrename entity old-name new-name) dictsearch (dictsearch entity name [flag])
;; Demonstrates how to create a dictionary (defun c:CreateDictionary ( / dict xname newdict datalist) (setq dict (list '(0 . "DICTIONARY") '(100 . "AcDbDictionary"))) (setq xname (entmakex dict)) (setq newdict (dictadd (namedobjdict) "MY_CUSTOM_DICT" xname)) (setq datalist (append (list '(0 . "XRECORD") '(100 . "AcDbXrecord")) '((1 . "Custom string") (10 5.0 5.0 0.0) (71 . 11)))) (setq xname (entmakex datalist)) (dictadd newdict "XREC_1" xname) (princ) ) ;; Deletes a custom dictionary (defun c:DeleteDictionary () (dictremove (namedobjdict) "MY_CUSTOM_DICT") ) ;; Prints the data from an Xrecord (defun c:printXrec ( / dictName dictEntry newdictlist xrec)

Description Adds a custom dictionary to the specified entity Removes a custom dictionary

Returns the next entry in a dictionary Renames a dictionary from the old name to a new name Searches a dictionary for an item

14

CP417-7: Leveraging ActiveX Libraries with AutoLISP

(setq dictName "MY_CUSTOM_DICT" dictEntry "XREC_1" ) (setq newdictlist (dictsearch (namedobjdict) dictName)) (setq xrec (cadr (member (cons 3 dictEntry) newdictlist))) (princ (entget (cdr xrec))) (princ) )

Monitoring Activity in AutoCAD with Reactors

AutoCAD monitors a lot of actions that take place in the application, while a drawing is open, and when objects are added to or modified in the drawing. Visual LISP allows you to step in and catch many of these actions through what is known as a reactor. Reactors come in a variety of types, some of the more common reactor types are listed in the following table. Reactor :VLR-AcDb-Reactor :VLR-Command-Reactor :VLR-DeepClone-Reactor :VLR-DocManager-Reactor :VLR-DWG-Reactor :VLR-DXF-Reactor :VLR-Editor-Reactor :VLR-Insert-Reactor :VLR-Linker-Reactor :VLR-Lisp-Reactor :VLR-Miscellaneous-Reactor :VLR-Mouse-Reactor :VLR-Object-Reactor :VLR-SysVar-Reactor :VLR-Toolbar-Reactor Description Database reactor Command reactor Deep clone reactor Document management reactor Drawing reactor (opening or closing a drawing file) DXF file handling reactor (reading and writing) General editor reactor (available for backwards compatibility) Block insertion reactor Linker reactor LISP reactor Reactors that are not part of other reactor types (pick first changes and layout switching) Mouse reactor (right-click and double-click) Object reactor (appending and modifying objects) System variable reactor Toolbar reactor (toolbar images change size) 15

CP417-7: Leveraging ActiveX Libraries with AutoLISP

:VLR-Undo-Reactor :VLR-Wblock-Reactor :VLR-Window-Reactor :VLR-XREF-Reactor

Undo reactor Writing a block reactor AutoCAD or drawing window reactor (window is moved or resized) XREF reactor (attaching, reloading, or detaching)

For more information about reactors, take a look at the AutoLISP Reference Guide in the AutoCAD online help. Important: When using reactors you cannot call a command using the Command function; this is due to the way reactors are designed. You must use the Visual LISP functions and the COM API to mimic the behavior of the commands that you need.

Command Reactor
Command reactors are one of the most commonly used reactors. They allow you to be notified when a command is started, ends, gets cancelled, or fails for some reason. The following sample code shows how to watch for a specific command, in this case the Hatch, and perform a task before the command even begins. ;; Check to see if our custom command reactors ;; have been loaded into the current drawing (if (= hyp-rctCmds nil) (setq hyp-rctCmds (vlr-command-reactor nil '((:vlr-commandCancelled . hyp-cmdAbort) (:vlr-commandEnded . hyp-cmdAbort) (:vlr-commandFailed . hyp-cmdAbort) (:vlr-commandWillStart . hyp-cmdStart) ) ) ) ) ;; Callback used when the user presses ESCape ;; or when the command ends by itself or due to ;; a problem (defun hyp-cmdAbort (param1 param2) (if (/= hyp-gClayer nil) (setvar "clayer" hyp-gClayer) ) (setq hyp-gClayer nil) 16

CP417-7: Leveraging ActiveX Libraries with AutoLISP

) ;; Callback used when a command is started (defun hyp-cmdStart (param1 param2) (setq hyp-gClayer (getvar "clayer")) (cond ((= (car param2) "QDIM")(prompt "\nQDIM started")) ((or (= (car param2) "HATCH") (= (car param2) "BHATCH") (= (car param2) "GRADIENT") ) (progn (if (= (tblsearch "layer" "Hatch") nil) (progn (setq acadObj (vlax-get-acad-object)) (setq docObj (vla-get-activedocument acadObj)) (setq layerObj (vla-add (vla-get-layers docObj) "Hatch")) (vla-put-color layerObj acRed) ) ) (setvar "clayer" "Hatch") ) ) ) )

Working with Windows

Microsoft creates many different APIs (Application Programming Interfaces) for themselves and other developers to take advantage of features found in Windows and the applications they develop. Since Visual LISP allows you to tap into COM libraries outside of AutoCAD, you can manipulate the features of Windows such as the file system and to collect information about the current user that is currently logged into the system and even the computer that the user is using.

17

CP417-7: Leveraging ActiveX Libraries with AutoLISP

Create Desktop Shortcut for AutoCAD


Below is an example of using the Windows Host Scripting Object to create a shortcut on the Desktop that allows you to use the /w command line switch to start AutoCAD with a specific workspace. Desktop shortcuts are one of many different ways to help enforce CAD standards and help to make the users life just a little bit easier, but since it can take time to setup icons on each computer they are often not used. The amount of configuration time is not a factor with the sample code, and it can be run at startup using a file like Acaddoc.lsp. ;; Create shortcut on desktop (defun c:CreateDesktopShortcut ( / wshShell desktopFldr myDocsFldr shrtObj) (if (= wshLibImport nil) (progn (vlax-import-type-library :tlb-filename "c:\\windows\\system32\\wshom.ocx" :methods-prefix "wshm-" :properties-prefix "wshp-" :constants-prefix "wshk-" ) (setq wshLibImport T) ) ) (setq wshShell (vlax-create-object "WScript.Shell")) (setq desktopFldr (wshm-Item (wshp-get-SpecialFolders wshShell) "Desktop")) (setq myDocsFldr (wshm-Item (wshp-get-SpecialFolders wshShell) "MyDocuments")) (setq shrtObj (wshm-CreateShortcut wshShell (strcat desktopFldr "\\My AutoCAD.lnk"))) (wshp-put-TargetPath shrtObj "\"C:\\Program Files\\Autodesk\\AutoCAD 2012 - English\\acad.exe\"") (wshp-put-Arguments shrtObj "/w \"3D Modeling\"") (wshp-put-Description shrtObj "Custom AutoCAD Desktop Shortcut") (wshp-put-WindowStyle shrtObj wshk-WshNormalFocus)

18

CP417-7: Leveraging ActiveX Libraries with AutoLISP

(wshp-put-HotKey shrtObj "Ctrl+Alt+A") (wshp-put-WorkingDirectory shrtObj myDocsFldr) (wshp-put-IconLocation shrtObj "C:\\Program Files\\Autodesk\\AutoCAD 2012 - English\\acad.exe, 0") (wshm-save shrtObj) (vlax-release-object wshShell) (princ) ) AutoCAD offers a number of different command line switches that can be used to control its start up behavior. Other popular and useful command line switches are /t to specify a drawing template for the default drawing that is created when AutoCAD first starts up and /p to specify the user profile that AutoCAD should use. To find out about these and other command line options in AutoCAD look up the topic Customize Startup in the AutoCAD online Help system. For additional information on the Windows Host Script Object, visit Microsofts website and do a search on Windows Script Documentation to download the help file for Windows scripting.

Working with Environment Variables


Environment variables are used to store information and settings about the current user logged into the machine, computer specific settings, or application specific settings. Some environment variables can be set or retrieved using AutoLISP with the Setenv and Getenv, but these functions are mainly limited to accessing some settings in the Windows Registry for AutoCAD and a few of the common Windows environment variables. By using the Windows Host Scripting Object, you can access all of the Windows environment variables and use strings with expandable variables contained in a string. By having access to the Windows environment variables, you can access and store custom settings outside of the Windows Registry. Environment variables are stored in two different ways; user or system. You use the keyword USER when you want to work with variables that are specific to the user that is currently logged in or SYSTEM to work with variables that are machine specific and are not user specific. To see which variables are available to you, launch a DOS prompt and enter the command SET. To see which variables are specific to you as a user, or the system go to Start (menu) >> Control Panel and double-click System. You might have to switch to the Classic View based on your current version of Windows operating system. For Windows Vista or Windows 7, click the 19

CP417-7: Leveraging ActiveX Libraries with AutoLISP

Advanced System Settings link on the left. In the System Properties dialog box, click the Advanced tab and then Environment Variables. In the Environment Variables dialog box, add, edit or remove the variables as desired. ;; Shows how to use expanding environment strings ;; Usage: (ExpEnvStr "%TEMP%\\MYDATA") ;; Results of sample: "C:\\DOCUME~1\\Lee\\LOCALS~1\\Temp\\MYDATA" (defun ExpEnvStr ( strVal / wshShell strValRet) (setq wshShell (vlax-create-object "WScript.Shell")) (setq strValRet (vlax-invoke-method wshShell 'ExpandEnvironmentStrings strVal)) (vlax-release-object wshShell) strValRet ) ;; Retreive the value of the environment variable ;; Usage: (GetEnvStr "SYSTEM" "USERID") ;; Alt Example: (GetEnvStr "SYSTEM" "PROCESSOR_ARCHITECTURE") (defun GetEnvStr ( strVarType strVarName / wshShell envVars strValRet) (setq wshShell (vlax-create-object "WScript.Shell")) (setq envVars (vlax-get-property wshShell 'Environment strVarType)) (setq strValRet (vlax-get-property envVars 'Item strVarName)) (vlax-release-object wshShell) strValRet ) ;; Set the value to an environment variable ;; Usage: (SetEnvStr "SYSTEM" "USERID" "L123") (defun SetEnvStr ( strVarType strVarName strVarVal / wshShell envVars) (setq wshShell (vlax-create-object "WScript.Shell")) (setq envVars (vlax-get-property wshShell 'Environment strVarType)) (vlax-put-property envVars 'Item strVarName strVarVal) (vlax-release-object wshShell) 20

CP417-7: Leveraging ActiveX Libraries with AutoLISP

(princ) )

Working with Microsoft Office

Being able to manipulate objects in AutoCAD and Windows can go a long way to improving workflow and help to decrease the number of redundant tasks that you might normally do every day. Being able to efficiently use your design information downstream can help a project get out faster and more cost effectively. Like you previously learned, Visual LISP is capable of working with other COM libraries and Microsoft offers many different COM libraries to work with its Microsoft Office applications such as Word and Excel. The following samples demonstrate Printing a Microsoft Word document to the default printer Showing how to take information from AutoCAD to create a Microsoft Word document Pushing and pulling information from an Microsoft Excel spreadsheet to modify content of a drawing Accessing information from a Microsoft Access (MDB) database

Print Documents through Word


If you are creating documents with Word dynamically and they need to be a part of a bid package, you will most likely want to have them printed and someone review them or maybe you want to have a user manual online and allow the user to print specific documents off for certain in-drawing conditions or assembly instructions. Whatever your reason might be, you can print a Word document off and the sample code below shows using a custom function to do just that. ;; Usage: (PrintMSWordDoc "c:\\datasets\\CP417-7\\data files\\spec1.doc") ;; Open a document in MS Word and print it using the default printer (defun PrintMSWordDoc (strWordDoc / wordObj wordDocsObj wordDocObj) (if (= wordLibImport nil) (progn (vlax-import-type-library :tlb-filename "C:\\Program Files\\Microsoft Office\\OFFICE12\\MSWORD.OLB" :methods-prefix "wordm-" :properties-prefix "wordp-" :constants-prefix "wordc-" ) (setq wordLibImport T) ) ) 21

CP417-7: Leveraging ActiveX Libraries with AutoLISP

(setq wordObj (vlax-create-object "Word.Application.12")) (setq wordDocsObj (vlax-get-property wordObj 'Documents)) (setq wordDocObj (wordm-open wordDocsObj strWordDoc)) (wordm-printout wordDocObj) (wordm-close wordDocObj wordc-wdDoNotSaveChanges) (wordm-quit wordObj wdDoNotSaveChanges) (vlax-release-object wordObj) (princ) )

Create new Word Document Based on Information in Drawing


Often when you create a drawing, you might also need to generate a quote based on the information contained in the drawing. Using the Microsoft Word COM library you can create a new document from scratch or even populate information into a document based on a template. The following sample code demonstrates how to create a new document from scratch and create a series of paragraphs that contain the names of the layers, dimension styles, text styles and blocks contained in the drawing. ;; Creates a new Word document and extracts styles from the current drawing. ;; The extracted information is added to the new Word document. (defun c:CreateMSWordDoc ( / acadObj docObj wordObj wordDocsObj wordDocObj wordParasObj wordParaObj wordParaRangeObj wordSentencesObj wordSentenceObj wordSentenceFontObj) (if (= wordLibImport nil) (progn (vlax-import-type-library :tlb-filename "C:\\Program Files\\Microsoft Office\\OFFICE12\\MSWORD.OLB" :methods-prefix "wordm-" :properties-prefix "wordp-" :constants-prefix "wordc-" ) (setq wordLibImport T) ) )

22

CP417-7: Leveraging ActiveX Libraries with AutoLISP

(setq acadObj (vlax-get-acad-object)) (setq docObj (vla-get-activedocument acadObj)) (setq (setq (setq (setq wordObj (vlax-create-object "Word.Application.12")) wordDocsObj (vlax-get-property wordObj 'Documents)) wordDocObj (wordm-Add wordDocsObj)) wordParasObj (wordp-get-paragraphs wordDocObj))

(setq wordParaObj (wordm-add wordParasObj)) (setq wordParaRangeObj (wordp-get-range wordParaObj)) (wordp-put-text wordParaRangeObj (strcat "Welcome to Autodesk University 2011" "\nWhat you are seeing is a very basic " "example of creating a Word document using " "the MS Word object. The example code creates " "a listing of layers, dimension styles, text " "styles and block names from the current " "drawing.\n\n")) (setq wordSentencesObj (wordp-get-sentences wordParaRangeObj)) (setq wordSentenceObj (wordm-item wordSentencesObj 1)) (setq wordSentenceFontObj (wordp-get-font wordSentenceObj)) (wordp-put-bold wordSentenceFontObj :vlax-true) (wordp-put-underline wordSentenceFontObj :vlax-true) (wordp-put-size wordSentenceFontObj 16) (setq wordParaObj (wordm-add wordParasObj)) (setq wordParaRangeObj (wordp-get-range wordParaObj)) (wordp-put-text wordParaRangeObj (strcat "Report from drawing: " (vla-get-fullname docObj) "\n\n")) (listItems (listItems (listItems (listItems (vla-get-layers docObj) "Layer List") (vla-get-dimstyles docObj) "Dimension Style List") (vla-get-textstyles docObj) "Text Style List") (vla-get-blocks docObj) "Block List")

(wordp-put-visible wordObj :vlax-true) (vlax-release-object wordObj) (princ) 23

CP417-7: Leveraging ActiveX Libraries with AutoLISP

) ;; Used to create a new paragraph based on the items in the collection ;; The title line is formatted as bold, underlined and a size of 14. (defun listItems (coll title / itemList wordParaObj wordParaRangeObj wordSentencesObj wordSentenceFontObj) (setq itemList "") (vlax-for for-item coll (setq itemList (strcat itemList "\n" (vla-get-name for-item))) ) (setq wordParaObj (wordm-add wordParasObj)) (setq wordParaRangeObj (wordp-get-range wordParaObj)) (wordp-put-text wordParaRangeObj (strcat title itemList "\n\n")) (setq wordSentencesObj (wordp-get-sentences wordParaRangeObj)) (setq wordSentenceObj (wordm-item wordSentencesObj 1)) (setq wordSentenceFontObj (wordp-get-font wordSentenceObj)) (wordp-put-bold wordSentenceFontObj :vlax-true) (wordp-put-underline wordSentenceFontObj :vlax-true) (wordp-put-size wordSentenceFontObj 14) )

Extract Information to Microsoft Excel Workbook


Microsoft Excel is a very powerful application that allows you to perform complex calculations or even create tables of information such as door and window schedules. The sample code below demonstrates the ability to extract information from a drawing. In this case it is the diameter of the circles in the drawing and their object handle. The object handle will be used to later update the objects in the drawing after the values in Microsoft Excel have been changed. ;; Creates a new Excel spreadsheet and extract the ;; circles from the current drawing. ;; The extracted information is added to the new Excel spreadsheet. (defun c:ExtractDrawingToExcel ( / acadObj docObj excelObj excelWorkbooksObj excelWorkbookObj excelWorksheetsObj excelWorksheetObj excelRangeObj spaceObj cnt for-item) (if (= excelLibImport nil) (progn 24

CP417-7: Leveraging ActiveX Libraries with AutoLISP

(vlax-import-type-library :tlb-filename "C:\\Program Files\\Microsoft Office\\OFFICE12\\Excel.exe" :methods-prefix "exlm-" :properties-prefix "exlp-" :constants-prefix "exlc-" ) (setq excelLibImport T) ) ) (setq acadObj (vlax-get-acad-object)) (setq docObj (vla-get-activedocument acadObj)) (setq excelObj (vlax-create-object "Excel.Application.12")) (exlp-put-visible excelObj :vlax-true) (setq excelWorkbooksObj (vlax-get-property excelObj 'Workbooks)) (setq excelWorkbookObj (exlm-add excelWorkbooksObj)) (setq excelWorksheetsObj (vlax-get-property excelWorkbookObj 'Worksheets)) (setq excelWorksheetObj (exlp-get-item excelWorksheetsObj 1)) (setq excelRangeObj (exlp-get-range excelWorksheetObj "A1")) (exlp-put-value2 excelRangeObj (vlax-make-variant "Welcome to AU 2011" vlax-vbstring)) (if (= (vla-get-activespace docObj) acModelSpace) (setq spaceObj (vla-get-modelspace docObj)) (setq spaceObj (vla-get-paperspace docObj)) ) (setq excelRangeObj (exlp-get-range excelWorksheetObj "A2")) (exlp-put-value2 excelRangeObj (vlax-make-variant "Handle" vlax-vbstring)) (setq excelRangeObj (exlp-get-range excelWorksheetObj "B2")) (exlp-put-value2 excelRangeObj (vlax-make-variant "Radius" vlax-vbstring)) (setq cnt 3) (vlax-for for-item spaceObj (if (= (vla-get-objectname for-item) "AcDbCircle") 25

CP417-7: Leveraging ActiveX Libraries with AutoLISP

(progn (setq excelRangeObj (exlp-get-range excelWorksheetObj (strcat "A" (itoa cnt)))) (exlp-put-value2 excelRangeObj (vlax-make-variant (vla-get-handle for-item) vlax-vbstring)) (setq excelRangeObj (exlp-get-range excelWorksheetObj (strcat "B" (itoa cnt)))) (exlp-put-value2 excelRangeObj (vlax-make-variant (vla-get-radius for-item) vlax-vbdouble)) (setq cnt (+ cnt 1)) ) ) ) (exlm-saveas excelWorkbookObj "c:\\datasets\\CP417-7\\data files\\circle-radius" exlc-xlNormal "" "" :vlax-false :vlax-true exlc-xlNoChange exlc-xlLocalSessionChanges :vlax-false "" "" :vlax-false) (vlax-release-object excelObj) (princ) ) ;; Opens an Excel spreadsheet and updates the entities in the ;; drawing based on the values in the spreadsheet. (defun c:UpdateDrawingFromExcel ( / acadObj docObj excelObj excelWorkbooksObj excelWorkbookObj excelWorksheetsObj excelWorksheetObj excelRangeObj strHandle ss cnt) (if (= excelLibImport nil) (progn (vlax-import-type-library :tlb-filename "C:\\Program Files\\Microsoft Office\\OFFICE12\\Excel.exe" :methods-prefix "exlm-" :properties-prefix "exlp-" :constants-prefix "exlc-" ) (setq excelLibImport T) 26

CP417-7: Leveraging ActiveX Libraries with AutoLISP

) ) (setq acadObj (vlax-get-acad-object)) (setq docObj (vla-get-activedocument acadObj)) (setq excelObj (vlax-create-object "Excel.Application.12")) (exlp-put-visible excelObj :vlax-true) (setq excelWorkbooksObj (vlax-get-property excelObj 'Workbooks)) (setq excelWorkbookObj (exlm-open excelWorkbooksObj "c:\\datasets\\CP417-7\\data files\\circle-radius")) (setq excelWorksheetsObj (vlax-get-property excelWorkbookObj 'Worksheets)) (setq excelWorksheetObj (exlp-get-item excelWorksheetsObj 1)) (setq excelRangeObj (exlp-get-range excelWorksheetObj "A3")) (setq cnt 3) (while (setq strHandle (vlax-variant-value (exlp-get-value2 excelRangeObj))) (setq ss (handent strHandle)) (setq obj (vlax-ename->vla-object ss)) (setq excelRangeObj (exlp-get-range excelWorksheetObj (strcat "B" (itoa cnt)))) (vla-put-radius obj (vlax-variant-value (exlp-get-value2 excelRangeObj))) (setq cnt (+ cnt 1)) (setq excelRangeObj (exlp-get-range excelWorksheetObj (strcat "A" (itoa cnt)))) ) (vlax-release-object excelObj) (princ) )

Work with Access Database using DAO


The DAO (Data Access Object) allows you to access data in a Microsoft Access database which can be used to populate the title block of a drawing or even keep track of project management 27

CP417-7: Leveraging ActiveX Libraries with AutoLISP

information. Microsoft Access databases are a great way to manage information in or from a drawing so it can be used downstream later to generate project quotes or manage information like building/IT assets. The sample code demonstrates how to utilize an Microsoft Access database that contains a single table and to step through the records contained in the table as well as update a field for one of the records in the table. ;; Opens an Access Database file and reports on the number of records in a table and ;; the records contained in the table. (defun c:AccessDatabase ( / daoObj dbObj rstObj fieldsObj) (if (= daoLibImport nil) (progn (vlax-import-type-library :tlb-filename "C:\\Program Files\\Common Files\\ Microsoft Shared\\DAO\\dao360.dll" :methods-prefix "daom-" :properties-prefix "daop-" :constants-prefix "daoc-" ) (setq daoLibImport T) ) ) (setq daoObj (vlax-create-object "DAO.DBEngine.36")) (setq dbObj (daom-opendatabase daoObj "c:\\datasets\\CP417-7\\data files\\AU2011.mdb")) (setq rstObj (daom-openrecordset dbObj "tblEmployees" daoc-dbOpenDynaset)) (daom-movefirst rstobj) (daom-movelast rstobj 0) (prompt (strcat "\n" (itoa (daop-get-recordcount rstObj)) " records in table.")) (daom-movefirst rstobj) (prompt "\n\nEmployee names") (while (= (daop-get-eof rstObj) :vlax-false) 28

CP417-7: Leveraging ActiveX Libraries with AutoLISP

(setq fieldsObj (daop-get-fields rstObj)) (prompt (strcat "\nFirst name: " (vlax-variant-value (daop-get-value (daop-get-item fieldsObj "FirstName"))))) (prompt (strcat "\nLast name: " (vlax-variant-value (daop-get-value (daop-get-item fieldsObj "LastName"))))) (terpri) (daom-movenext rstobj) ) (daom-movefirst rstobj) (daom-findfirst rstobj "FirstName='Bob'") (if (= (daop-get-nomatch rstobj) :vlax-true) (prompt "\nNo matching record") (progn (setq fieldsObj (daop-get-fields rstobj)) (prompt (strcat "\nBob was in room " (vlax-variant-value (daop-get-value (daop-get-item fieldsObj "RoomNumber"))))) (terpri) (daom-edit rstobj) (daop-put-value (daop-get-item fieldsObj "RoomNumber") "103A") (prompt "but is now in room 103A.\n") (daom-update rstobj 1 0) (princ) ) ) (daom-close rstobj) (daom-close dbObj) (vlax-release-object daoObj) 29

CP417-7: Leveraging ActiveX Libraries with AutoLISP

(gc) (princ) )

Where to Get More Information

When you are first start using the functionality found in an ActiveX library, you will most likely have some questions and where you go to find answers might not be clear. The following is a list of resources that you can use to get help: o Help System The AutoLISP Reference Guide in the AutoCAD online Help system contains information on using some of the COM related functions, but you will also need to turn to the AutoCAD ActiveX Reference Guide. To access the AutoLISP Reference Guide, go to: http://exchange.autodesk.com/autocad/enu/help. The AutoCAD ActiveX
Reference Guide can be found at C:\Program Files\Common Files\Autodesk Shared\ acadauto.chm.

Autodesk Discussion Forums The Autodesk forums provide peer-to-peer networking and some interaction with Autodesk moderators. You can ask a question about anything in AutoCAD and get a response from a fellow user or Autodesk employee. To access the discussion forums, go to http://forums.autodesk.com, click AutoCAD, and then click one of the links for a subgroup. AUGI Forums The AUGI forums provide peer-to-peer networking where you can ask questions about virtually anything in AutoCAD and get a response from a fellow user. Visit AUGI at http://www.augi.com. Industry Events and Classes Industry events such as AUGI CAD Camp and Autodesk University are great places to learn about new features in an Autodesk product. Along with industry events, you might also be able to find classes at your local technical college or Autodesk Authorized Training Center (ATC). Internet There are samples and tutorials on the Internet that demonstrate other aspects of the AutoCAD and Microsoft Office ActiveX libraries. Use your favorite search engine, such as Google or Bing and search on the topic of interest.

30

You might also like