Open drawing from DLL form freezes VBA?

Discussion in 'AutoCAD' started by Norman Yuan, Oct 18, 2004.

  1. Norman Yuan

    Norman Yuan Guest

    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?
     
    Norman Yuan, Oct 18, 2004
    #1
  2. 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)?
     
    Tony Tanzillo, Oct 19, 2004
    #2
  3. Norman Yuan

    Norman Yuan Guest

    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)
     
    Norman Yuan, Oct 19, 2004
    #3
  4. I'm not talking about how you use the DLL, I mean
    how do you start the VBA macro?
     
    Tony Tanzillo, Oct 19, 2004
    #4
  5. Norman Yuan

    Norman Yuan Guest

    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.
     
    Norman Yuan, Oct 20, 2004
    #5
  6. 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...
     
    Mike Tuersley, Oct 20, 2004
    #6
  7. Huh?
     
    Tony Tanzillo, Oct 20, 2004
    #7
  8. 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 Tanzillo, Oct 20, 2004
    #8
  9. Mike,

    Why is it bad practice referencing DLL in DVB?

    Regards,
    Maksim Sestic
     
    Maksim Sestic, Oct 20, 2004
    #9
  10. Norman Yuan

    Norman Yuan Guest

    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.
     
    Norman Yuan, Oct 20, 2004
    #10
  11. 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).
     
    Tony Tanzillo, Oct 20, 2004
    #11
  12. 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...
     
    Mike Tuersley, Oct 21, 2004
    #12
  13. 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...
     
    Mike Tuersley, Oct 21, 2004
    #13
  14. Who told you that?
     
    Tony Tanzillo, Oct 22, 2004
    #14
  15. With VBA, ALL ActiveX DLLs are in-process servers,
    regardless of how you load them.
     
    Tony Tanzillo, Oct 22, 2004
    #15
  16. 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...
     
    Mike Tuersley, Oct 22, 2004
    #16
  17. 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...
     
    Mike Tuersley, Oct 22, 2004
    #17
  18. 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.



     
    Tony Tanzillo, Oct 22, 2004
    #18
  19. 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...
     
    Mike Tuersley, Oct 22, 2004
    #19
  20. Norman Yuan

    Norman Yuan Guest

    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.
     
    Norman Yuan, Oct 24, 2004
    #20
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.