Late Binding of AutoCAD Type Library

jonno_g

Registered User.
Local time
Today, 09:22
Joined
May 30, 2007
Messages
52
Hi,

I'm really hoping somebody can help with this....

I have an Access database that contains code to extract information from AutoCAD and populate the database fields with it. Currently I have the 'acax18enu.tlb' AutoCAD 2010 type library referenced in the VBA project, but this causes a problem when the database is opened on a machine that doesn't have AutoCAD installed. (Obviously the type library does not exist on these machines, so the database will refuse to run because of the missing type library.)

What I am trying to do is late bind the library so that it is no longer loaded as a reference in the VBA project, but at run-time instead. Through other measures, this piece of code is unlikely to be executed on a machine without AutoCAD, and this way even if it is I can trap it and flag the problem to the user before it runs.

This is what I have so far, and it works fine. It opens AutoCAD if necessary and then opens the relevant drawing file. The problem comes after that...

Code:
Dim DB As DAO.Database
Dim RS As DAO.Recordset
Dim strSQL As String
Dim objAcadApp As Object
Dim strProjNo as string
Dim strDWGNo as string
Dim strDWGName As String
dim boolDWGPresent as Boolean
Dim strPath As String
Dim strFileExists As String
 
Me.ProjectNumber.SetFocus
strProjNo = Me.ProjectNumber.Text
 
Me.DWG.SetFocus
strDWGNo = Me.DWG.Text
 
If strProjNo <> "" Then
    strDWGName = strDWGNo & "-" & strProjNo & ".dwg"
Else
    strDWGName = strDWGNo & ".dwg"
End If
 
On Error Resume Next
Set objAcadApp = GetObject(, "AutoCAD.Application")
If Err <> 0 Then
    strSQL = "SELECT txtAutoCADPath FROM tblLocalOptions WHERE PrimaryKey = 1"
    Set DB = CurrentDb
    Set RS = DB.OpenRecordset(strSQL)
    On Error Resume Next
    RetVal = ShellExecute(hwnd, "open", RS!txtAutoCADPath, "", _
      "N:\DWG\", SW_SHOWMAXIMISED)
    While objAcadApp.Name <> "AutoCAD"
        Set objAcadApp = GetObject(, "AutoCAD.Application")
    Wend
    objAcadApp.Visible = True
    objAcadApp.WindowState = acMax
End If
 
Set objAcadDocs = objAcadApp.Documents
For Each objEachDwg In objAcadDocs
    If objEachDwg.Name = strDWGName Then
        Set objThisDwg = objEachDwg
        boolDWGPresent = 1
        Exit For
    Else
        boolDWGPresent = 0
    End If
Next
 
If boolDWGPresent = 0 Then
    strPath = "N:\DWG\" & Format$(((Int(strDWGNo / 500)) * 500), "00000") & "-" & Format$(((Int(strDWGNo / 500)) * 500) + 499, "00000") & "\"
    strFileExists = Dir(strPath & strDWGName)
    If strFileExists <> "" Then
        objAcadApp.Documents.Open (strPath & strDWGName)
    Else
        MsgBox "No Drawing File Exists.", vbCritical
        Exit Sub
    End If
    Set objAcadDocs = objAcadApp.Documents
    For Each objEachDwg In objAcadDocs
        If objEachDwg.Name = strDWGName Then
            Set objThisDwg = objEachDwg
            Exit For
        Else
        End If
    Next
Else
End If
 
objThisDwg.Activate
 
Set objLayout = objThisDwg.ActiveLayout

If I then try to do anything further with the entities within the drawing file I strike problems. This next piece of code follows immediately after the above snippet, and the second line of this piece is where the trouble starts.

Code:
For Each objEnt In objLayout.Block
    If TypeOf objEnt Is AcadBlockReference Then
        Set objBlock = objEnt
        With objBlock
            If .Name = "FOR_CONSTRUCTION" Then
                strStatus = "For Construction"
            Else
            End If
        End With
    End If
Next

The line "If TypeOf objEnt Is AcadBlockReference Then" returns the error "Compile error: User-defined type not defined".

This is starting to get beyond the current limits of my VBA knowledge. It would appear to me that I have one of two conditions present. Either i) By late binding the AutoCAD 2010 Type Library VBA does not make available all elements of said library, or ii) By using the approach that I have shown above I am in fact not biinding the AutoCAD 2010 Type Library, but another library that has less functionality than the one that I thought I was using.

Do either of these ideas make sense to those who are more experienced than me? Or have I completely missed the boat? Should I be using a different approach altogether?
 
Try changing:
Code:
If TypeOf objEnt Is AcadBlockReference Then
...to:
Code:
If objEnt.EntityName = "AcadBlockReference" Then
 
Try changing:
Code:
If TypeOf objEnt Is AcadBlockReference Then
...to:
Code:
If objEnt.EntityName = "AcadBlockReference" Then


Close! So very, very close!!!

Code:
If objEnt.EntityName = "[B]AcDb[/B]BlockReference" Then

This does the trick! Thankyou VERY MUCH!!! :D:D:D

I've been struggling with this for DAYS - it's almost embarassing to see that such a small change was all that was holding me up.

I must ask - How did you know that that was what the problem was? Have you hit the same wall before?

Cheers,...Jon.
 
I actually obtained the information from AutoCAD's Visual Basic Reference Help Files. I simply did a search for AcDbBlockReference (yes, I forgot to correct the typo in my post), and it showed me sample code using the EntityName attribute.
 
I actually obtained the information from AutoCAD's Visual Basic Reference Help Files. I simply did a search for AcDbBlockReference (yes, I forgot to correct the typo in my post), and it showed me sample code using the EntityName attribute.

Which version of AutoCAD do you have? Mine (2010) is very light on for VBA examples using AcDbBlockReference. (Plenty with AcadBlockReference though.)

After your pointing me in the right direction, I managed to figure it out by trying it with "AcadBlockReference" and seeing that it wasn't getting any of the attribute information, then I put in a
Code:
MsgBox objEnt.entityname
and stepped through all of the entities in the paperspace layout until I found a block and saw that its entityname was "AcDbBlockReference" and it dawned on me then.

I still have my suspicions that by late binding I'm not using the acax18enu.tlb, but some other library instead - problem is I've no idea what or how to find out.
 
It depends which library is actively registered. You can find this out through the Windows Registry:

Get the ClassID for AutoCAD.Application:
HKEY_CLASSES_ROOT\AutoCAD.Application\CLSID
(Default) {28B7AA99-C0F9-4C47-995E-8A8D729603A1}

Get the TypeLib for the ClassID you found:
HKEY_CLASSES_ROOT\CLSID\{28B7AA99-C0F9-4C47-995E-8A8D729603A1}\TypeLib
(Default) {851A4561-F4EC-4631-9B0C-E7DC407512C9}

Get the file path for the TypeLib:
HKEY_CLASSES_ROOT\TypeLib\{851A4561-F4EC-4631-9B0C-E7DC407512C9}\1.0\0\win32
(Default) C:\Program Files\Common Files\Autodesk Shared\acax18enu.tlb

This is the type library that will be referenced when you instantiate an AutoCAD.Application object via late-binding.
 
OK, I'm still a little confused. (Thanks for your help, though, I'm learning a huge amount this week!)

I followed your instructions in the above post and got to this:

Key Name: HKEY_CLASSES_ROOT\TypeLib\{E072BCE4-9027-4F86-BAE2-EF119FD0A0D3}\1.0\409\win32
Data: C:\Program Files\Common Files\Autodesk Shared\acax18enu.tlb

So I am, in fact, using the same type library as I would be had I early bound it.

Why, then, does it require different code when late bound as opposed to early bound? :confused:
 
With early binding, using the AutoCAD Object Library in Visual Basic References, you have the AcDbBlockReference object type available. With late binding, not including the Library in the VB References, you do not have the AcDbBlockReference object type, in which case the code will not compile correctly.

In any event, with either binding method, checking the EntityName attribute will yield the desired result.
 

Users who are viewing this thread

Back
Top Bottom