AutoCAD开发常见问题
版本老了点,是R14的不过有些还有用张朝阳 <BR> Autodesk China <BR> 问:有什么方式可以在AutoCAD启动的时候自动加载VBA工程? <BR> 答:当VBA加载时会在AutoCAD目录下寻找一个名叫acad.dvb的工程。如果找到,就会自动加载它。如果你想VBA和缺省工程在AutoCAD启动的时候每次都加载,你需要在acad.rx文件中生成一个入?。VBA被设计成命令加载方式(在没有激活一个VBA命令之前不占用任何内存和进程)。为了总是加载VBA和acad.dvb工程,请在acad.rx文件中包含下列一行:
acadvba.arx <BR> 在AutoCAD <BR> 2000中支持嵌入工程,这样当你打开拥有嵌入工程的图形文件时该工程就会自动加载。所以定义嵌入工程也是一个很好的自动加载VBA工程的办法。 <BR> 问:有办法可以在AutoCAD启动时自动运行一个VBA例程或宏吗?
答:当然。你可以从AutoCAD的acad.lsp文件的启动功能中通过VBARUN的命令行版本运行一个工程中的宏。首先,你需要准备acad.dvb文件以便自动加载。以drawline.dvb作为例子,用VBALOAD命令弹出VBA <BR> IDE对话框。然后用VBA <BR> IDE保存为菜单命令保存此工程为新的名字acad.dvb。下一步,激活notepad.exe并且建立或添加下列行到acad.lsp文件中: <BR> (defun S::STARTUP() (command "_-vbarun" "drawline")) <BR> 问: AutoCAD支持VBA多工程的打开吗? <BR> 答:在2000中支持。但在14版中尚不支持。 <BR> 问:我可以加密我的VBA模块代码吗? <BR> 答:虽然VBA不支持可执行文件的创建,但是它确实在一个工程的基础上提供了口令保护工程窗体、类和模块可见性的功能。你可以发现这个工程保护功能在VBA <BR> IDE菜单中。选择 工具 > 工程属性 > 保护。如下图所示:
问:在VBA中如何在命令行上提示? <BR> 答:有一些方法允许在命令行提示输入以获取数据。这些方法以“GET”开头。你可以发现决大多数的方法(如果不是全部的话)通过对象浏览器搜索AutoCAD类型库。启动VBA <BR> IDE。击F2功能键或者从视图菜单中选择对象浏览器。?对象浏览器窗口中使用库范围下拉列表把缺省的<所有库>改成AutoCAD。库列表下面的编辑列表框是用来搜索的。输入GET到那个编辑列表框中并且敲回车键。包含“GET”的类和成员函数就会显示在滚动列表中。AcadUtility的一些成员函数可以?命令行上提示用户输入。如下图所示: 问:我怎样从AutoCAD菜单中激活一个VBA例程? <BR> 答:你需要编辑菜单和添加VBARUN模块子例程。首先确认正确的VBA工程已经加载。 <BR> 问:我怎样从AutoCAD菜单中启动一个VBA对话框(窗体)? <BR> 答:除了创建一个VBA窗体,你还需要创建一个VBA子例程来显示这个窗体。而这个子例程需要用VBARUN命令激活。1. 启动VBA IDE;2. <BR> 从菜单中选择 插入 > 用户窗体(缺省名称为UserForm1);3. 添加合适的控件到你的窗体中; 4. 下一步,从菜单中选择 插入 > <BR> 模块;5. 输入以下的代码到缺省的Module1模块中:Sub Foo() UserForm1.showEnd Sub6. <BR> 最后,编辑AutoCAD菜单调用以下命令来激活对话框: -VBARUN Module1.foo. <BR> 问:我已经写了一个VBA例程用ThisDrawing.Utility.GetPoint获取一个点。当我从一个VBA对话框中启动这个例程时,我可以在命令行上看到提示。但是我不能在AutoCAD屏幕上点取一个点。我作错了什么?
答:首先需要关闭对话框,然后才能从AutoCAD获取数据。添加以下的代码到ThisDrawing.Utility.GetPoint之前的任何地方以关闭对话框,然后你就可以获得一个点了。
Me.Hide <BR> 问:有方法加载一个VBA工程而在加载后不显示VBA IDE吗?
答:如果你设置AutoCAD系统变量FILEDIA为0,或者在你加载一个工程的时候把<打开VBA编辑器>的开关关闭,你就不会?加载之后看到VBA <BR> IDE了。这是一个标准的AutoCAD转换机制。 <BR> 问:VBA和AutoLISP有何不同,两者如何转换? <BR> 答:如果你已经熟知AutoLISP并且想学习VBA,通过把VBA和AutoLISP表达式联系起来的方法就可以容易地做到。以下就是一个关于两种语言的比较。由于大量的AutoLISP代码可以利用,转换一个已有的AutoLISP代码段为VBA远比重新编制VBA代码来得容易。如果两者的变量名字保持一致,那么比较两者的代码也就变得容易了。
点: <BR> 在AutoLISP中,你用(setq)函数来设置一个点。下面这一行把点(0,0,0)分配给PT1变量。(0,0,0)代表这个点位置的x,y,z坐标。
(setq PT1 '(0 0 0)) <BR> 在VBA中,这个操作需要更多的代码行来完成: <BR> Dim PT1(0 To 2) As Double <BR> PT1(0) = 0# <BR> PT1(1) = 0# <BR> PT1(2) = 0# <BR> 在VBA中,你使用Dim语句来声明变量。点总是保存在一个三维双精度值数组中。一个数组也就是一个变量列表。在数组中的变量都拥有相同的名字。数组中的第一个元素使用索引值0,即PT1(0)。第二个元素使用索引值1,即PT1(1)。依次类推。
VBA使用#号作为双精度值类型的后缀字符。在这个数组中,PT1(0)保存x坐标值,PT1(1)保存y坐标值,PT1(2)保存z坐标值。 <BR> 既然你已经知道如何保存一个点,我们就可以写一个VBA宏来在两点之间画一条线。 <BR> 在AutoLISP中,你使用(defun)来定义一个名叫Line1的T诤智暗腃: <BR> 意味着拥护可以直接从AutoCAD命令行上执行这个函数。下一步,分配两个点,然后用AutoCAD的LINE命令?两点之间画一条线了。 <BR> 在VBA中,一个子例程创建一个与AutoLISP相当的函数。下面是AutoLISP和VBA的源代码。 <BR> AutoLISP code <BR> <BR>(defun C:LINE1 ()<BR>(setq PT1 '(0 0 0)) <BR>(setq PT2 '(4 4 0))<BR>(command "._line" PT1 PT2 "")<BR>)
VBA code <BR> <BR>Sub Line1()<BR>Dim NewLine As Object<BR>Dim PT1(0 To 2) As Double<BR>Dim PT2(0 To 2) As Double<BR>PT1(0) = 0#<BR>PT1(1) = 0#<BR>PT1(2) = 0#<BR>PT2(0) = 4#<BR>PT2(1) = 4#<BR>PT2(2) = 0#<BR>Set NewLine = ModelSpace.AddLine(PT1, PT2)<BR>End Sub
子例程的第一行声明变量NewLine为一个对象。对象是一个应用程序的一个元素。线,视图和层都是对象的例子。下一步,点数组声明了两个点值。最后,AutoCAD从(0,0,0)到(4,4,0)画一条线。添加一条线到模型空间中,你需要使用ModelSpace对象集合中的AddLine方法和一条线的起始和终止点。
获取点: <BR> 用AutoLISP,你经常需要提示拥护选择一个点。你可以在VBA中用Utility对象的GetPoint方法达到这个目的。你需要声明一个额外的VarRet变量来保存返回值。以下是Line2的AutoLISP和VBA的代码对照: AutoLISP code <BR> <BR>(defun C:LINE2 ()<BR>(setq PT1 (getpoint "\nStart Point: ")) <BR>(setq PT2 (getpoint PT1 "\nEnd Point: "))<BR>(command "._line" PT1 PT2 "")<BR>)
VBA code <BR> <BR>Sub Line2()<BR>Dim VarRet As Variant<BR>Dim NewLine As Object<BR>Dim PT1(0 To 2) As Double<BR>Dim PT2(0 To 2) As Double<BR>VarRet = Utility.GetPoint(, "Start Point: ")<BR>PT1(0) = VarRet(0)<BR>PT1(1) = VarRet(1)<BR>PT1(2) = VarRet(2)<BR>VarRet = Utility.GetPoint(PT1, "End Point: ")<BR>PT2(0) = VarRet(0)<BR>PT2(1) = VarRet(1)<BR>PT2(2) = VarRet(2)<BR>Set NewLine = ModelSpace.AddLine(PT1, PT2)<BR>End Sub
这一次,GetPoint方法返回一个Variant数据类型。这种数据类型可以保存任何类型的数据。为了使用你选择的并且保存在变量VarRet之中的开始和终止点,你必须转换Variant数据为一个双精度值的数组并且把他们付值给PT1和PT2。
现在两个VBA子例程已经建立起来了,如何运行它们呢? <BR> 启动AutoCAD,打开一个新图; <BR> 加载工程; <BR> 选择 工具|宏|运行宏; <BR> 选择宏位置(缺省为所有活动图形和工程); <BR> 5. 从窗口中选择宏名称; <BR> 6. 点击运行按钮。 AutoCAD开发常见问题(二)
张朝阳 <BR> Autodesk China <BR> <BR> 问:能够给AutoCAD的VBA宏传递参数吗? <BR> 答:从AutoCAD直接传递参数到一个VBA宏中是不可能的。但是你可以用VBA的GetString 方法和LISP的(command)函数来传递信息。
举例: <BR> 首先定义一个VBA宏: <BR> Sub testparams() <BR> Dim str, str2 As String <BR> str=ThisDrawing.Utility.GetString(False) <BR> str2=ThisDrawing.Utility.GetString(False) <BR> MsgBox str <BR> MsgBox str2 <BR> End Sub <BR> 然后用以下LISP语句调用此宏: <BR> (command "-VBARUN" "testparams" "param1" "param2") <BR> <BR> 问:.MNU和.LSP文件的调用顺序是怎样的? <BR> 答:他们在AutoCAD 2000的调用顺序是这样的: <BR> 当AutoCAD启动时: <BR> - acadr2000.lsp <BR> - acad.lsp <BR> 对于每个新打开的文档: <BR> - acad.lsp, 如果在AutoCAD的配置对话框中的系统标签下做了相应的选项设定。 <BR> - acaddoc2000.lsp <BR> - acaddoc.lsp <BR> - .MNU菜单文件和它们的关联.MNL文件。 <BR> 问:我已经写了一个VisualLisp函数和一个VBA宏。这个VBA宏显示一个对话框,并且有一些按钮允许有用户输入(例如:输入一个字符串)。现在我从VisualLisp用(vl-vbarun)调用这个VBA宏。当AutoCAD执行到这一行时,LISP停在这一行。但是一旦我在此宏中使用了一个用户输入函数,LISP就不等VBA对话框出现,而继续执行下面的LISP函数。有些时候甚至首先执行LISP的输入函数,然后再执行VBA宏中的输入语句。怎样才能使我的LISP函数和VBA宏同步?
答:现在只有一个解决办法。在你的LISP函数中(vl-vbarun) <BR> 函数必须最后调用。当关闭VBA对话框或者从VBA宏中返回时,你得调用另一个你想继续执行的LISP函数。你可以象下面这样做。 <BR> 首先:你需要一个LISP函数调用这个VBA宏: <BR> (defun c:test () <BR> ;; Call a VBA macro which displays <BR> ;; a dialog and writes a file. <BR> (vl-vbarun "test") <BR> ;;If you uncomment the following line, then AutoCAD will prompt you <BR> ;;to select an entity first, input a string second. <BR> ;;(entsel) <BR> (princ) <BR> ) <BR> 然后你需要第二个LISP函数以供你的VBA宏返回时调用: <BR> (defun c:test_cont () <BR> ;; Here you can continue. <BR> (print “ I am continuing.”) <BR> (princ) <BR> ) <BR> 以下是这个VBA宏的示例: <BR> Sub test() <BR> ' Show a dialog which uses some <BR> ' user input functions. <BR> UserForm1.Show <BR> ' Call the lisp function which should <BR> ' be now executed. <BR> ' You can use the SendCommand method: <BR> ' ThisDrawing.SendCommand ("test_cont ") <BR> ' or use the ActiveX interface of VisualLisp: <BR> ' In order to use it, please remember to reference vl.tlb file which is in <BR> Acad2000 folder <BR> ' into your VBA project and execute (vl-load-com) on the AutoCAD command <BR> line first. <BR> Dim vl As Object <BR> Set vl = CreateObject("VL.Application.1") <BR> vl.ActiveDocument.functions.Item("c:test_cont").funcall <BR> End Sub <BR> <BR> 问:怎样用Visual Basic生成一个用户接口模块以供Visual LISP方便地调用? <BR> 答:最简单和最有效的方法是为AutoCAD写一个内过程(in-process)的自动客户(Automation Client)。例如:一个VB <BR> ActiveX DLL。这个DLL 以后可以从 Visual LISP, VBA, Java <BR> (通过Automation)和ObjectARX加载。它可以是一个AutoCAD的自动客户,也可以是一个任何的自动服务器( Automation <BR> server),或者多重服务器。 <BR> 1. 启动Visual Basic 5 or 6; <BR> 2. 在New Project Wizard中选择ActiveX DLL; <BR> 3. 把工程名改为"MyProject"; <BR> 4. 在工程中有一个缺省的类模块,把它的名称改为"MyClass"; <BR> 5. 添加一个函数或者子例程到类模块中。例如: <BR> ' This function takes two arguments, and will return a list of data to the <BR> calling function <BR> Public Function MyFn(ByRef arg1 as Integer, ByRef arg2 as Double) As <BR> Variant <BR> myForm.Show vbModal <BR> ' Create a list of items to return to the caller (the items are in this <BR> case purely arbitrary) <BR> MyFn = Array(1.0,"Arbitrary string",2) <BR> End Function <BR> (这里,myForm是一个你必须添加到工程中的表格。同时切记MyFn是一个函数,它将返回一个值或者一组值给调用例程。) <BR> 6. 点取File -> Make <BR> MyProject.dll。这就会生成一个DLL并且把它注册为COM。(如果你想在其他机器上运行此DLL,你需要首先确认在所有的机器上安装并注册了这个DLL。这通常需要你用Visual <BR> Basic生成一个安装包。) <BR> 7. 如果你想从Visual LISP中使用此DLL,你需要定义一个简单的函数,并且把他加载到AutoCAD中: <BR> (defun showDialog (/ acadApp vbApp retVal retList) <BR> ;; required in AutoCAD 2000, not R14 <BR> (if (car (atoms-family 1 '("vl-load-com"))) (vl-load-com)) <BR> ;; get the main AutoCAD application object <BR> (setq acadApp (vlax-get-acad-object)) <BR> ;; load VB ActiveX DLL into AutoCAD's address space (either line will <BR> work) <BR> ;;(setq vbApp (vlax-invoke acadApp "GetInterfaceObject" <BR> "MyProject.MyClass") <BR> (setq vbApp (vla-GetInterfaceObject acadApp "MyProject.MyClass")) <BR> (if (not vbApp) <BR> (princ "\nError loading ActiveX DLL.") <BR> (vlax-invoke vbApp "MyFn" <BR> 7 ; arg1, an integer <BR> 1.5 ; arg2, a 'double' <BR> ) <BR> ) <BR> ) <BR> 为了调用已经暴露出的ActiveX方法,在命令行上输入: <BR> (showDialog) <BR> 将把下列内容返回给AutoCAD: <BR> (1.0 "Arbitrary string" 2) <BR> 你会发现你可以给VB对话框传递参数并且在AutoCAD中处理返回值。这对于生成选项对话框非常有用,因为有些参数需要初始化并且修改后的值需要返回给AutoCAD。
7. 如果你想从VBA使用这个DLL,你需要把此DLL添加到引用中。(用COM注册它,就会把它添加到ActiveX <BR> 服务器的列表中。然后它就可以被VBA引用,不然就请浏览并且选择MyProject.dll。) <BR> 8. 然后你就可以用下面的机制加载这个内过程 ActiveX DLL,并且调用其中的函数: <BR> Sub MyVBAProject() <BR> Dim oMyApp as Object <BR> dim vReturn as Variant <BR> set oMyApp = ThisDrawing.Application.GetInterfaceObject( <BR> "MyProject.MyClass" <BR> ) <BR> vReturn = oMyApp.MyFn(7,1.5) <BR> End Sub <BR> <BR> 问:可以在VBA中获得带有预览图象的AutoCAD "Open File Dialog"对话框吗? <BR> 答:在VBA没有直接的方法这样做。但是,你可以通过LISP和AutoCAD之间的通讯来完成。在LISP中有一个名叫getfiled的函数,它可以预览DWG并且与AutoCAD的"Open <BR> File Dialog"表现一样。 <BR> 首先,通过SendCommand方法发送getfiled表达式给AutoCAD命令行并且定义一个系统变量USERS1以保存文件名。然后,你可以用GetVariable方法获得这个系统变量。最后,象使用其它任何变量一样使用它。
Public Sub OpenDialog() <BR> Dim fileName As String <BR> ThisDrawing.SendCommand "(setvar " & """users1""" & "(getfiled " & <BR> """Select a DWG File""" & """c:/program files/acad2000/""" & """dwg""" & <BR> "8)) " <BR> fileName = ThisDrawing.GetVariable("users1") <BR> MsgBox "You have selected " & fileName & "!!!", , "File Message" <BR> End Sub <BR> 问: <BR> 如何在AutoLISP调用完一个VBA宏后,卸载包含它的VBA工程?我想首先加载这个工程,调用一个宏,然后卸载它。下面是我使用的代码,但是VBAUNLOAD在Test宏结束之前被发送到命令行。
(command "-VBARUN" "Test") <BR> (command "vbaunload") <BR> 答:主要的问题是你的宏当中有要求用户输入的语句,这时LISP试图执行下一条命令,即VBAUNLOAD。我们需要等待LISP语句执行完毕,或者让LISP在调用VBARUN命令后什么也不做,而让VBA卸载它自己。下面是这两种方法:
1) 在LISP中等待。 <BR> (defun c:RunMacro( / oldFileDia oldCmdEcho) <BR> (setq oldFileDia (getvar "FILEDIA") <BR> oldCmdEcho (getvar "CMDECHO") <BR> ) <BR> (setvar "FILEDIA" 0) <BR> (setvar "CMDECHO" 0) <BR> (command "_VBALOAD" "c:\\test.dvb") <BR> (command "_-VBARUN" "Test") <BR> (while (= "-VBARUN" (getvar "CMDNAMES")) <BR> (command pause) <BR> ) <BR> (command "_VBAUNLOAD") <BR> (setvar "FILEDIA" oldFileDia) <BR> (setvar "CMDECHO" oldCmdEcho) <BR> (princ) <BR> ) <BR> 2) VBA中自动卸载。 <BR> 你可以使VBA代码强制卸载它自己。在你的宏的最后(例如:UserForm_Terminate()),使用下列代码可以达到此目的: <BR> AppActivate ThisDrawing.Application.Caption <BR> SendKeys "_VBAUNLOAD" + Chr$(13) <BR> 以上的代码在AutoCAD R14.01中工作良好,但是AutoCAD <BR> 2000允许加载多个工程。相应地,VBAUNLOAD增加了一个额外参数。有两个新的函数可以加载和运行VBA <BR> 代码:(vl-vbaload)和(vl-vbarun)。你可以通过在宏名中指定工程名字把这两种操作联合在一起。 <BR> (defun c:RunMacro2000( / oldFileDia oldCmdEcho) <BR> (setq oldFileDia (getvar "FILEDIA") <BR> oldCmdEcho (getvar "CMDECHO") <BR> ) <BR> (setvar "FILEDIA" 0) <BR> (setvar "CMDECHO" 0) <BR> (vl-vbarun "c:\\test.dvb!Test") <BR> (while (= "-VBARUN" (getvar "CMDNAMES")) <BR> (command pause) <BR> ) <BR> (command "VBAUNLOAD" "c:\\test.dvb") <BR> (setvar "FILEDIA" oldFileDia) <BR> (setvar "CMDECHO" oldCmdEcho) <BR> (princ) <BR> ) <BR> 第二种方法也需要做一些小的改动。我们可以通过自动接口向AutoCAD发送命令,并且这比SendKeys更安全: <BR> ThisDrawing.SendCommand "_VBAUNLOAD C:\TEST.DVB" + Chr$(13) <BR> 如果我们卸载另一个工程,我们可以使用自动接口 (ThisDrawing.Application.UnloadDVB "test.dvb" <BR> )。但是在这种情况下我们需要使用SendKeys或SendCommand来卸载其本身。 <BR> <BR> 问:在R13中,我可以通过检查DWK文件知道DWG文件是否被锁定了。在R14中,没有一个ARX函数来检查文件锁定状态。有什么其它办法吗? <BR> 答:因为我们现在使用了操作系统支持的文件锁定方式,你可以通过用_fsopen()打开图形文件来检查文件是否锁定。使用模式"r+"和共享标志SH_DENYWR,如果失败,这个图形就已经被打开并且是写的状态。如果成功,千万不要忘记关闭此文件,然后再让AutoCAD打开它。
同时你也需要检查.DWK文件,因为这个文件也可能被另外的R13例程所打开。 <BR> 2) 用LISP运行一些VBA代码打开这个文件,通过一个系统变量返回一个成功或者失败标志给LISP。例如:下面的VBA代码可以做这件事情。 <BR> Sub Test_File_Data() <BR> Dim FileNum As Integer <BR> Dim MyFileName As String <BR> Dim sysVarName As String <BR> Dim sysVarData As Variant <BR> On Error GoTo ErrHandler <BR> FileNum = 1 <BR> MyFileName = "D:\PROGRAM FILES\AUTOCAD R14\ARCTEXT.DWG" <BR> sysVarName = "USERI1" <BR> sysVarData = 0 <BR> ThisDrawing.SetVariable sysVarName, sysVarData <BR> Open MyFileName For Binary Access Read Lock Read Write As FileNum <BR> Close 1 <BR> sysVarData = 1 <BR> ThisDrawing.SetVariable sysVarName, sysVarData <BR> Exit Sub <BR> ErrHandler: <BR> MsgBox "Error Number = " & Err.Number <BR> MsgBox "Error Description = " & Err.Description <BR> Err.Clear <BR> sysVarData = 0 <BR> ThisDrawing.SetVariable sysVarName, sysVarData <BR> End Sub <BR> 问:有什么方法可以检测一个VBA宏是否加载? <BR> 答:在AutoCAD <BR> 2000中,你可以获取一个属性名叫VBE的ActiveX应用程序对象。它使你可以访问VBAIDE扩展对象。这个对象拥有方法和属性允许你判断一个工程是否已经加载。
如果你想深入学习,就请启动VBAIDE,添加一个对"Microsoft Visual Basic for Applications <BR> Extensibility"的引用,然后你就可以在你的ObjectBrowser (F2)浏览此对象了。 <BR> 以下是四个例子。第一个"loadMyProcedure"检测所有已经加载的工程名。如果没有发现"TestMenuEcho",就加载它。 <BR> 第二个例子"testMacros"在每一个加载的模块中搜索每一行并且在立即窗口中 (cntrl + <BR> G)打印true或者false。目的在于寻找文本"test4"(宏的名字)。 <BR> 第三个例子"displayLoadedProjects"在信息窗口中显示所有已加载的工程。 <BR> 第四个例子是一个LISP例程。它使用相同的ActiveX对象判断一个工程是否已经加载,如果没有,就加载它。 <BR> Public Sub loadMyProcedure() <BR> Dim int1 As Integer <BR> Dim bProjectLoaded As Boolean <BR> ' Iterate through all the projects <BR> For int1 = 1 To Application.VBE.VBProjects.Count <BR> ' Make the test boolean variable to true if the Project I want to load <BR> ' is already loaded, Change TestMenuEcho to the name of your project <BR> If Application.VBE.VBProjects(int1).Name = "TestMenuEcho" Then <BR> ' Debug.Print Application.VBE.VBProjects(int1).Name <BR> bProjectLoaded = True <BR> End If <BR> Next int1 <BR> ' Display a message if my the project is already loaded <BR> ' if it isn't then load it, change the directory and <BR> ' name to that of your project <BR> If bProjectLoaded = True Then <BR> MsgBox "TestMenuEcho is already loaded" <BR> Else <BR> MsgBox "Going to load the project TestMenuEcho" <BR> Application.LoadDVB "D:\Vba-apps\a-2000\menuecho in menu.dvb" <BR> End If <BR> End Sub <BR> <BR> Public Sub testMacros() <BR> Dim int1 As Integer <BR> Dim int2 As Integer <BR> ' Iterate through all the loaded projects <BR> For int1 = 1 To Application.VBE.VBProjects.Count <BR> ' Name of loaded project <BR> Debug.Print Application.VBE.VBProjects(int1).Name <BR> ' Iterate through the text of each module looking for "test4" <BR> For int2 = 1 To Application.VBE.VBProjects(int1).VBComponents.Count <BR> ' Get the number of lines in each module - use in the <BR> ' find method below <BR> Dim L As Long <BR> L = Application.VBE.VBProjects(int1).VBComponents(int2) _ <BR> .CodeModule.CountOfLines <BR> Debug.Print Application.VBE.VBProjects(int1).VBComponents(int2) _ <BR> .CodeModule.Find("test4", 1, 1, L, 1, False, False) <BR> Next int2 <BR> Next int1 <BR> End Sub <BR> <BR> Public Sub displayLoadedProjects() <BR> Dim strProjectNames <BR> Dim int1 As Integer <BR> strProjectNames = "Names of loaded projects " & vbCrLf <BR> For int1 = 1 To Application.VBE.VBProjects.Count <BR> strProjectNames = strProjectNames + Application.VBE.VBProjects(int1).Name <BR> & vbCrLf <BR> Next int1 <BR> MsgBox strProjectNames <BR> End Sub <BR> (defun c:loadMyProject () <BR> ;; This routine will load a project if it is not already loaded <BR> ;; the VBE (VB extensibility) ActiveX object is used to reference <BR> ;; the loaded projects <BR> ;; Load ActiveX <BR> (vl-load-com) <BR> ;; Get the VBE extisibility object <BR> (setq acadObject (vlax-get-acad-object)) <BR> (setq acadVbe (vla-get-vbe acadObject)) <BR> (setq acadVbeProjects (vlax-get-property acadVbe 'VBProjects)) <BR> ;; Get the number of loaded VBA projects <BR> (setq int1 (vlax-get-property acadVbeProjects 'count)) <BR> ;; Counter and test variable named loaded <BR> (setq int2 1) <BR> (setq loaded "False") <BR> ;; Repeat for each project <BR> (repeat int1 <BR> ;; Itereate through the projects, getting the name of <BR> ;; next project, each time through <BR> (setq Item (vlax-invoke-method acadVbeProjects 'Item int2)) <BR> (setq pName (vlax-get-property Item 'Name)) <BR> <BR> ;; Test the name for the name of the project I want to load <BR> ;; If it is already loaded the set the test variable to True <BR> (if (= pName "my_test_project") <BR> (progn <BR> (prompt "\nmy_test_project is already loaded\n") <BR> (Setq Loaded "True") <BR> ) <BR> ) <BR> ;; Increment the number used to get the next Project <BR> (setq int2 (+ int2 1)) <BR> ) <BR> ;; Load project if it is not already loaded by testing <BR> ;; the Loaded variable <BR> (if (= Loaded "False") <BR> (progn <BR> (princ "\nLoading my_test_project") <BR> (command "-VBALOAD" <BR> "D:/vba-apps/a-2000/already loaded test.dvb" <BR> ) <BR> ) <BR> <BR> 附:我已将所有本文中的VBA和VLISP代码及此文打包成一个ZIP压缩文件。你可以从以下的网址免费下载。 <BR> <A href="http://china.autodesk.com/support/china.html" target="_blank" >http://china.autodesk.com/support/china.html</A>的‘文件下载’ <BR> AutoCAD开发常见问题AutoCAD开发常见问题(三) <BR>张朝阳 (Bill Zhang) <BR> <BR>问:我想对一个圆弧进行操作。但是当我运行下面的VBA宏时,出现一个编号为451的运行错误。它的意思是‘对象不是一个集合’。这是一个关于变体型数组(Variant <BR>Array)的常见VBA问题吗?有什么方法可以解决? <BR>Sub showArcPoints() <BR>Dim oEnt As Object <BR>For Each oEnt In ThisDrawing.ModelSpace <BR>If (TypeOf oEnt Is AcadArc) Then <BR>' This causes Runtime error 451 - Object Not a Collection <BR>' if oEnt is not late bound it works ok <BR>MsgBox "StartPoint(0) is =" & oEnt.StartPoint(0) <BR>End If <BR>Next <BR>End Sub <BR>答:当VBA从一个一般对象返回变体型数组的时候,如果这个对象是晚束缚(late <BR>bound)的话,VBA不能通过这个对象的属性返回数组的一个元素。如果这个对象是早束缚(early bound)的话,那么就不受限制。 <BR>有两种办法可以解决这个问题。其一、用AcadArc 来对此对象进行早束缚。修改好的代码如下: <BR>Sub showArcPoints() <BR>Dim oEnt As Object <BR>Dim oArc As AcadArc <BR>For Each oEnt In ThisDrawing.ModelSpace <BR>If (TypeOf oEnt Is AcadArc) Then <BR>'This works well since it is early bound. <BR>Set oArc = oEnt <BR>MsgBox "StartPoint(0) = " & oArc.StartPoint(0) <BR>End If <BR>Next <BR>End Sub <BR>其二、声明一个临时的变体型变量并且把它设置为需要操作的对象属性。修改的代码如下: <BR>Sub showArcPoints() <BR>Dim oEnt As Object <BR>For Each oEnt In ThisDrawing.ModelSpace <BR>If (TypeOf oEnt Is AcadArc) Then <BR>'This also works well. <BR>Dim pv_temp As Variant <BR>pv_temp = oEnt.StartPoint <BR>MsgBox "StartPoint(0) = " & pv_temp(0) <BR>End If <BR>Next <BR>End Sub <BR> 问:我想在VBA中使用Microsoft的DAO。如何使用? <BR>答:请注意DAO并不是随VBA提供的。所以首先你必须确认DAO在所有需要它运行的机器上正确安装。并且你得使用相应的Microsoft方法来获得DAO的使用许可,然后才可以使用。你会发现位于Microsoft网站上的这篇文档也许有用:
<A href="http://msdn.microsoft.com/library/techart/msdn_redistmdac.htm" target="_blank" >http://msdn.microsoft.com/library/techart/msdn_redistmdac.htm</A> <BR>根据不同版本的DAO安装在不同版本的AutoCAD上,安装程序将覆盖一个MFC <BR>DLL文件MFC42.DLL。这可能引起AutoCAD或者其他的应用程序的一些问题。所以请小心对待。如果你已经正确安装了DAO,下列的VBA代码应该运行良好。这是一个用VBA在AutoCAD中访问Microsoft <BR>Access MDB数据库的例子。 <BR>Private Sub CommandButton1_Click() <BR>Dim daoWs As Workspace <BR>Dim daoDb As Database <BR>Dim daoRs As Recordset <BR>Dim daoFields As Fields <BR>Dim recordValue As String <BR>' Create a DAO workspace object <BR>Set daoWs = CreateWorkspace("", "admin", "", dbUseJet) <BR>' Open a MDB file (and get a database object) <BR>Set daoDb = daoWs.OpenDatabase("") <BR>' Get a recordset from the database <BR>Set daoRs = daoDb.OpenRecordset("") <BR>' Move to the first record in this set <BR>daoRs.MoveFirst <BR>' Get all fields from the first record <BR>Set daoFields = daoRs.Fields <BR>' Get the value from one field. <BR>' For the index you can use an integer <BR>' or the name of the table field. <BR>recordValue = daoFields("") <BR>MsgBox ("Value: " & recordValue) <BR>' <BR>' Close every DAO object <BR>' <BR>' Close the recordset object <BR>daoRs.Close <BR>' Close the database object <BR>daoDb.Close <BR>' Close the workspace object <BR>daoWs.Close <BR>End Sub <BR>问:我怎样在AutoCAD中调用具有参数的VBA函数?我知道VB/A宏没有参数。Microsoft就是这样设计的。然而,VB/A函数可以带参数。我想知道是否存在命令行或者LISP的一种途径来调用VBA函数以便从AutoCAD传递必需的参数。
答:在AutoCAD R14中, 这是不可能的。但是在AutoCAD <BR>2000利用VBASTMT命令可以完成这项任务。这种方法仅当所调用的函数(f_test)定义在一个VBA模块中,而不是在ThisDrawing对象中有效。以下的例子说明如何具体去做。这个函数需要一个字符串参数。
Function f_test(ByVal sCommand As String) <BR>MsgBox "This was sent from the AutoCAD Command Line: " & sCommand <BR>End Function <BR>在AutoCAD命令行,用VBASTMT命令。 <BR>Command: vbastmt <BR>Expression: f_test "line 1,1 5,5 " <BR>或者用以下的LISP代码: <BR>(command "vbastmt" "f_test \"line 1,1 5,5 \"") <BR>问:块(Block)对象的AddDimAligned方法创建不正确的标注(Dimension)对象。我怎样才能正确地添加一个标注(Dimension)实体到一个块(Block)对象中?
答:块对象的AddDimAligned方法和其它的AddDimxxx方法导致添加的标注实体不正确。这是已知的一个AutoCAD缺陷。然而,下面的方法可以克服这个缺陷。首先,在模型空间中生成一个标注实体,拷贝这个实体到所需块对象中,最后,删掉原始的标注实体。以下的事例代码生成一个块"test",然后添加了一个DimRotated实体到块中,最后把这个块插入到模型空间中。
Sub f_SolAddDiminBlocks() <BR>'Work around for Adding dimensions to block AutoCAD 2000 <BR>Dim po_rotDim As AcadDimAligned <BR>Dim po_block As AcadBlock <BR>Dim pd_ext1(0 To 2) As Double <BR>Dim pd_ext2(0 To 2) As Double <BR>Dim pd_lineLoc(0 To 2) As Double <BR>Dim po_array(0) As Object <BR>pd_ext1(0) = 3: pd_ext1(1) = 3: pd_ext1(2) = 0 <BR>pd_ext2(0) = 10: pd_ext2(1) = 3: pd_ext2(2) = 0 <BR>pd_lineLoc(0) = 5: pd_lineLoc(1) = 4: pd_lineLoc(2) = 0 <BR>'create dimeionsion object <BR>Set po_rotDim = ThisDrawing.ModelSpace.AddDimAligned(pd_ext1, pd_ext2, <BR>pd_lineLoc) <BR>'create a new block by name test <BR>Set po_block = ThisDrawing.Blocks.Add(pd_ext1, "test") <BR>'insert a block reference <BR>ThisDrawing.ModelSpace.InsertBlock pd_ext1, "test", 1, 1, 1, 0 <BR>'copy dimension object <BR>Set po_array(0) = po_rotDim <BR>ThisDrawing.CopyObjects po_array, po_block <BR>po_rotDim.Delete <BR>'release the references <BR>Set po_block = Nothing <BR>Set po_rotDim = Nothing <BR>End Sub <BR>问:怎样才能获得当前配置的AutoCAD绘图仪列表? <BR>答:下面的VBA函数列举出所有的PC3的绘图仪。你可以在你的应用程序中使用它。 <BR>Public Function GetPlotters() As Collection <BR>Set GetPlotters = New Collection <BR>Dim strPlotter As String <BR>strPlotter = Dir(Application.Preferences.Files.PrinterConfigPath + "\*.pc3") <BR>While Not strPlotter = "" <BR>GetPlotters.Add strPlotter <BR>strPlotter = Dir <BR>Wend <BR>End Function <BR>有一个方法用来枚举所有的系统打印机。这些打印机在AutoCAD的绘图对话框中也可以使用。请参看Microsoft知识库文档: Q166008 在以下的网页: <BR> 有什么方式可以
页:
[1]