Loading VBA Files with Visual LISP
There are two AutoCAD functions that you would use to Load and Run VBA Applications namely, VBALOAD and VBARUN. In a menu file you would use them like this :
[Test]^C^C^C^P-vbaload test.dvb -vbarun Module1.MyTest
Or, in an AutoLisp routine, you would write something like this :
(command "vbaload" "test.dvb") (command "-vbarun" "Module1.MyTest")
The VBALOAD function has one serious flaw though! If a VBA application is already loaded, and you run VBALOAD again, you get an error message. Try it out :
Command: -vbaload Initializing VBA System... Open VBA Project: test.dvb
Now try and load it again.
Command: -vbaload Open VBA Project: test.dvb
You should get an error message :
"File already loaded d:/drawings/test.dvb"
This is where Visual Lisp comes into play.
The function (VL-VBALOAD) behaves much like the command VBALOAD. You need to supply the file name of a project or DVB file. The complete file name should be provided along with the path and DVB extension. For example, if you want to load a project named MyProject.dvb in the C:\MyWork\ folder, the (VL-VBALOAD) function call would appear as follows :
You should note a couple of things right away. Visual LISP makes use of forward slashes when separating folder or directory names. Also, the parentheses are required and the extension DVB is needed for the project to be properly located.
Unlike the VBALOAD command, this function will not generate an error if the project has already been loaded into the current drawing environment. Thus, programs can proceed smoothly by just calling the load function and then calling the run function without concern about the project already being loaded. Another interesting feature is that the Enable Macros/Virus Warning message does not appear when you use the Visual LISP approach.
Therefore, your menu macro :
[Test]^C^C^C^P-vbaload test.dvb -vbarun MyTest
…can be replaced with the following one :
[Test]^C^C^C^P(vl-vbaload "test.dvb")(vl-vbarun "MyTest")
And of course, your AutoLisp coding should be replaced with this :
(vl-vbaload "test.dvb") (vl-vbarun "MyTest")
Here's a little function that you could load at startup to help you locate, load and run VBA files :
;CODING START HERE (defun VBA-LOADIT (ProjName Macro) (if (findfile ProjName) (progn (vl-vbaload ProjName) (vl-vbarun Macro) );progn );if (princ) );defun (princ) ;CODING ENDS HERE
(vbaloadit "dvb-file" "macro")
(vbaloadit "test.dvb" "MyTest")
You must keep some other considerations in mind when using (VL-VBALOAD) and (VL-VBARUN). For example, after you invoke the (VL-VBARUN) function, the Visual LISP function will continue to run and can (will) interfere with the VBA interface if you try to do too much. On the other hand, there are some distinct advantages to using the Visual LISP approach to loading and launching VBA macros instead of the command-line versions when programming a menu- or toolbar-based interface.
One thing to note is that the VBARUN is not a subroutine. That is, program execution will not be handed to the VBA macro and the Visual LISP routine suspended as if it were running a function. Instead, the Visual LISP function will continue to run as the VBA macro starts. The best thing to do is simply finish the Visual LISP function as quickly as possible and let the VBA macro run the command interface from that point forward. If you want to return to a Visual LISP function after running the VBA code, then use the SendCommand method attached to the Document object in VBA. When you are ready to hand control back to Visual LISP, call the function directly (remember to wrap parentheses around the command start up for direct launches of Visual LISP functions). When you use this approach, the VBA program should end and allow the Visual LISP function to proceed without interference. Similar to starting the VBA macro in the first place, when you send commands to the AutoCAD document from VBA, they will be run along with the VBA and sometimes this can result in confusion at the user level as the two try to take turns. Note that you can pass parameters from VBA to the Visual LISP function by sending them as part of the command stream. They will need to be converted to strings first, then sent to the Visual LISP function as part of the function start up from the Send Command method.
Note : Sorry, but due to additions to the Object Model, this next section will only work in AutoCAD 2002 and above.
Want to know what Projects are loaded in your drawing?
Type this at the console prompt :
_$ (vl-load-com) _$ (setq oApp (vlax-get-acad-object)) VLA-OBJECT IAcadApplication 00ac8928> _$ (setq oVbe (vlax-get oapp "VBE")) #<VLA-OBJECT VBE 020b9c18> _$ (vlax-dump-object oVBE T) ; VBE: nil ; Property values: ; ActiveCodePane = nil ; ActiveVBProject = #<VLA-OBJECT _VBProject 020ba620> ; ActiveWindow (RO) = nil ; CodePanes (RO) = #<VLA-OBJECT _CodePanes 00b1c2e0> ; CommandBars (RO) = #<VLA-OBJECT _CommandBars 030b2a24> ; Events (RO) = #<VLA-OBJECT Events 020b9c94> ; MainWindow (RO) = #<VLA-OBJECT Window 020b8ce8> ; SelectedVBComponent (RO) = #<VLA-OBJECT _VBComponent 020ba748> ; VBProjects (RO) = #<VLA-OBJECT _VBProjects 020b9c4c> ; Version (RO) = "5.00" ; Windows (RO) = #<VLA-OBJECT _Windows 020b9d18> ; No methods T
I presume you can see what I see? A "VBProjects" property. Now that's interesting! But how do we extract the loaded Projects?
Load and run this small routine :
;CODING STARTS HERE (defun Gvba ( /oApp oVBE oProjs N Nams oProj) (vl-load-com) ;requires automation links (if (and Drill down to the Projects object (setq oApp (vlax-get-acad-object)) (setq oVBE (vla-get-vbe oApp)) (setq oProjs (vlax-get oVBE "VBProjects")) ) ;Loop through Projects object (repeat (setq N (vla-get-count oProjs)) ;get the item at position N (setq oProj (vla-item oProjs N) ;get the name property, ;add it to the list. Nams (cons (list (vlax-get oProj "Name") (vlax-get oProj "FileName") ) Nams) N (1- N))) ) ; return list of names Nams );defun ;CODING ENDS HERE
You should have a list of Projects in the variable "Nams".
And, would you like to Unload all projects within your drawing? Try this :
;CODING STARTS HERE (defun C:UNLOADALLVBA ( / VBAProjs VBAProj) (setq VBAProjs (Gvba)) (foreach VBAProj VBAProjs (command "_VBAUNLOAD" (cadr VBAProj))) ) ;CODING ENDS HERE