I am doing a VB DLL project, trying to put some drawing processing functionalities in a DLL library. I run into a problem when using form in the DLL. I need to open and close drawing(s) from the DLL. For some operation, I need to show a form in the DLL (modal form, of course). User click controls on the form could open and then close drawing(s). But, the opening/closing drawing(s) performed, Acad's VBA editor freezes, while Acad drawing editor is still working. If the form in the dll is called again, the form shows and then freezes. But, if you call a VBA form, the VBA form is OK, although VBA editor is now frozen. This freezing thing does not occur if you open/close drawing from DLL directly (i.e. not through form in DLL). Try following code if anyone would verify and could find a workaround: 1. Start a VB6 DLL project ("Project1") and rename the Class1 as "OpenDwgTest" and copy following code to the class Option Explicit Private mDwg As AcadDocument Public Sub OpenDwgTest(dwgName As String, acadApp As AcadApplication) Load Form1 Set Form1.CadApp = acadApp Form1.DwgName = dwgName Form1.Show vbModal End Sub 2. In the DLL project, add a small form ("Form1"), place a button "Command1" on it, and then copy following code to it: Option Explicit Private mDwgName As String Private mAcad As AcadApplication Private mDwg As AcadDocument Property Let DwgName(vData As String) mDwgName = vData End Property Property Set CadApp(vData As AcadApplication) Set mAcad = vData End Property Private Sub Command1_Click() Set mDwg = mAcad.Documents.Open(mDwgName) End Sub Private Sub Form_Unload(Cancel As Integer) mDwg.Close False Set mDwg = Nothing Set mAcad = Nothing MsgBox "form unloaded and dwg closed.", vbInformation End Sub 3. Compile the dll 4. Start a VBA project in Acad, set reference to Project1, and add a module, copy following code to the module: Public Sub TestDLL() Dim testDll As Project1.DwgTest Set testDll = New Project1.DwgTest testDll.OpenDwgTest "C:\Temp\TestDrawing.dwg", ThisDrawing.Application End Sub 5. Run the macro "TestDLL". The form in DLL will be shown; Click button will open the "TestDrawing.dwg"; Close the form by clicking "x" on the form, the opened drawing will be closed. 6. enter "VBAIDE" in command line to get into VBA Editor. You will find VBA is frozen, but Acad drawing editor is still working. 7. If you run the "TestDLL" again, the form is shown and then freezes 8. You can add a userform in the VBA project, and make another macro the show this form. After first call to "TestDLL", although VBA is frozen, you can still open/close the UserForm in VBA project as long as you do not call "TestDLL" again. I tried on Acad2002 and Acad2004, got the same result. Anyone has explanation to this?
5. Run the macro "TestDLL". The form in DLL will be shown; Click button VBA code and any ActiveX code that it calls can behave differently depending on how you start the VBA macro. How are you doing that (from the IDE; using VBARUN, etc)?
Here is how I use the DLL in Acad VBA: a macro: (See my previously posted code) Public Sub TestDLL() Dim testDll As Project1.DwgTest '''Create the DLL class object '''A form in DLL is a member of the class, get "new-ed" here Set testDll = New Project1.DwgTest '''This method shows a modal form in the DLL, pssing in a dwg file name and AcadApplication reference '''On the form, user click a button that opens a dwg, do something and close it '''A close button will hide the form testDll.OpenDwgTest "C:\Temp\TestDrawing.dwg", ThisDrawing.Application '''The form in DLL class get unloaded here '''Not really necessary, the object goes out of scope anyway. Just used to it. Set testDll=Nothing End Sub I also tried to make a UserForm in VBA and use a button on the userform to host the code in above macro. The same result: once user open a drawing from the DLL form, VBA freezes. Actually, on the DLL form, uer has choices of processing current drawing, drawings in particular folder, or drawings in particauler folder and all sub folders underneath. For processing current drawing, there is no problem, you could run it many times. For other two options, I can not show the DLL form more than once because of frozen VBA (On Acad2000i, Acad2002 and Acad2004)
Both from Acad menu "Tools->Macro..." and command line "VBARUN" in Acad drawing editor. Also did in VBA IDE from menu "Tools->Macro...". The same result.
1. Don't pass the reference ThisDrawing.Application to your DLL use GetObject to acquire the reference from within your DLL 2. Don't add a reference to your DLL in your DVB. Use GetInterfaceObject. In order to do this, look in your AutoCAD Sample directory for the ActiveX sample project [dvb & vbp] -- Mike ___________________________ Mike Tuersley CADalyst's CAD Clinic Rand IMAGINiT Technologies ___________________________ the trick is to realize that there is no spoon...
Load the following LISP code, and use the VBARUNX command it defines to start your VBA macro, and see if that changes anything: (defun C:VBARUNX () (vl-load-com) (vla-runmacro (vlax-get-acad-object) (getstring "\nMacro name: ") ) (princ) )
Tony, thanks. I tried your "VBARUNX" lisp command. The result is interesting: 1. after I specify the macro name, the DLL form is shown, and it IS modal, as any VBA userform (Acad menu is grayed out). 2. I click a button on the form. The Button_Click() code does: open a drawing; do something (I use a messagebox, representing the process); and then close the drawing. What really happens here is: a. The newly opened drawing loses its focus once it is opened and hides behind existing drawing. I tried set the opened drawing as ActiveDocument in DLL form code, doesn't work. b. Once a drawing is opened from the dll form, Acad itself (or Acad drawing editor) becomes "semi-activitated". That is, Acad's menu becomes enabled: you can click menu items and toolbars, but no action is taken with one examption: Acad's menu "Window" menu is fully functional (with the dll form being shown), you can tile/cascade/switch drawing windows. c. if you close the dll form at this time (click "x" on the form, or a button on the form with "Unload me" or Me.Hide"), the form dispears (but not unloaded, see following explanation), but Acad's command line is blank, meaning a process/command is pending. I have to hit "Esc" key several times to release Acad from the hijacking, then the unloading code in the dll form runs (I buried amessahe box in the DLL form's Form_Unload() procedure, so I can tell). OK, so far, the VBA Editor DOES NOT freeze. It seems the problem is I need to find a owner for the DLL modal form. I've already had some idea to try later today and I'll post back the result.
When you use this method to run VBA code, it is subject to the same restrictions that LISP code is, namely that you cannot open/close drawings or switch documents. You also cannot hide your form to get input (this is an unexplainable VB limitation that has something to do with how VB forms work - in Delphi for example, I have no problem doing that).
2. Don't add a reference to your DLL in your DVB. Use GetInterfaceObject. Why add the reference? Since he is obviously having issues he should follow the sample app provided by Adesk that works. From there, he can "back away" into his own thing and troubleshoot his own problem Besides that, since he hasn't written a control why add a reference to it??? It serves only one purpose -- intellisense. If you use GetInterfaceObject its easier catch the ensuing error as opposed to a missing reference. -- Mike ___________________________ Mike Tuersley CADalyst's CAD Clinic Rand IMAGINiT Technologies ___________________________ the trick is to realize that there is no spoon...
Why is it bad practice referencing DLL in DVB? Its just personal opinion/preference Maxim. If you haven't written a control, why add a reference to it??? It serves only one purpose -- intellisense. If you use GetInterfaceObject its easier to catch an error as opposed to a missing reference. It also helps keep the DLL in-process. -- Mike ___________________________ Mike Tuersley CADalyst's CAD Clinic Rand IMAGINiT Technologies ___________________________ the trick is to realize that there is no spoon...
It [a reference] serves only one purpose -- intellisense. What I meant by serving only 1 purpose was 1 purpose beyond what the GIO option gives you. Is there another reason to use referencing over GIO? -- Mike ___________________________ Mike Tuersley CADalyst's CAD Clinic Rand IMAGINiT Technologies ___________________________ the trick is to realize that there is no spoon...
With VBA, ALL ActiveX DLLs are in-process servers, True, "It also helps keep the DLL in-process." was an errant statement. Thanks for correcting me there! -- Mike ___________________________ Mike Tuersley CADalyst's CAD Clinic Rand IMAGINiT Technologies ___________________________ the trick is to realize that there is no spoon...
Sorry, this isn't making any sense. It is not a question of "GIO" verses references. It is a question of late- verses early- binding. Early bnding has performance advantages, because unlike late binding, where method DISPIDs must be looked up on each call (or dynamicaly cached so they are only looked up on the first call to each method), early binding allows DISPIDs to be cached at compile time, eliminating very costly, dynamic, runtime DISPID lookups. Regardless of this, the main point of my original comment is that the use of early or late binding has no relevance to the problem the original poster is experieincing.
Sorry, this isn't making any sense. Yeah, sorry, it is getting weird - not enough sleep on my part. That's where I was steering away from. Per his code, his problem appears to be his errant passing of the app object around. I was trying to get him to start with a solid working example and expand from there. Some how I ended up in this weird thread with you - sorry about that =( -- Mike ___________________________ Mike Tuersley CADalyst's CAD Clinic Rand IMAGINiT Technologies ___________________________ the trick is to realize that there is no spoon...
As I promised I would post back on how I solve the problem. Well, after several days working on some other more urgent things with the problem hanging on in my mind, I could not find a solution to use DLL form to open/close drawing(s) without freezing Acad VBA. So I decide to work around it by making the entire form in DLL as an ActiveX control (*.ocx). Granted, this approach works. Originally, if the DLL Form way worked, the code in Acad VBA world be simpler: you only need to create a DLL class instance, set a few properties and then call a method that brings up the DLL form in Acad. With ActiveX control, now you need to add a UserForm in Acad and then place the control on it, set some properties of the control. and then write a macro to call up the userform. Compare to using DLL form, you need one extra step: place the control on a user form. Fortunately, all operation is done with the control, the userform only need to be shaped to hold the control ad add a "Close" button to it. So it is still fairly simple to use.